synapsecns/sanguine

View on GitHub
agents/contracts/notarymanager/notarymanager.contractinfo.json

Summary

Maintainability
Test Coverage
{"solidity/NotaryManager.sol:AbstractGuardRegistry":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"}],"userDoc":{"events":{"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."}},"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"AbstractGuardRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:AbstractNotaryRegistry":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"}],"userDoc":{"events":{"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"AbstractNotaryRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202d8251e138fe0b5086afd25e7b9e0da1f52c856fa3ff55f47bdbbeef2f4413a864736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202d8251e138fe0b5086afd25e7b9e0da1f52c856fa3ff55f47bdbbeef2f4413a864736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"197171:8111:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;197171:8111:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"197171:8111:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Address\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:AddressUpgradeable":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f1390d161456d895fa438a0f48187e166bef6d7e832bd664ec8d7226c47f3c7464736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f1390d161456d895fa438a0f48187e166bef6d7e832bd664ec8d7226c47f3c7464736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"171950:7122:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;171950:7122:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"171950:7122:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"AddressUpgradeable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Attestation":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122055365cf1f844f9b66d435286ff1b4be1e63391c5e9f5f0831b4f3d366ffe772e64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122055365cf1f844f9b66d435286ff1b4be1e63391c5e9f5f0831b4f3d366ffe772e64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"47827:7639:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;47827:7639:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"47827:7639:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"OFFSET_ORIGIN":{"details":"AttestationData memory layout [000 .. 004): origin         uint32   4 bytes [004 .. 008): destination    uint32   4 bytes [008 .. 012): nonce          uint32   4 bytes [012 .. 044): root           bytes32 32 bytes      Attestation memory layout [000 .. 044): attData        bytes   44 bytes (see above) [044 .. 109): signature      bytes   65 bytes (65 bytes)"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"OFFSET_ORIGIN\":{\"details\":\"AttestationData memory layout [000 .. 004): origin         uint32   4 bytes [004 .. 008): destination    uint32   4 bytes [008 .. 012): nonce          uint32   4 bytes [012 .. 044): root           bytes32 32 bytes      Attestation memory layout [000 .. 044): attData        bytes   44 bytes (see above) [044 .. 109): signature      bytes   65 bytes (65 bytes)\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Attestation\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:AttestationHub":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"AttestationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"},{"inputs":[{"internalType":"bytes","name":"_attestation","type":"bytes"}],"name":"submitAttestation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"events":{"AttestationAccepted(address,bytes)":{"notice":"Emitted when an attestation is submitted to AttestationHub."},"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{"submitAttestation(bytes)":{"notice":"Called by the external agent. Submits the signed attestation for handling."}},"version":1},"developerDoc":{"kind":"dev","methods":{"submitAttestation(bytes)":{"details":"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.","params":{"_attestation":"Payload with Attestation data and signature (see Attestation.sol)"},"returns":{"_0":"TRUE if Attestation was handled correctly."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"AttestationAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_attestation\",\"type\":\"bytes\"}],\"name\":\"submitAttestation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"submitAttestation(bytes)\":{\"details\":\"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.\",\"params\":{\"_attestation\":\"Payload with Attestation data and signature (see Attestation.sol)\"},\"returns\":{\"_0\":\"TRUE if Attestation was handled correctly.\"}}},\"version\":1},\"userdoc\":{\"events\":{\"AttestationAccepted(address,bytes)\":{\"notice\":\"Emitted when an attestation is submitted to AttestationHub.\"},\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{\"submitAttestation(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed attestation for handling.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"AttestationHub\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"submitAttestation(bytes)":"f646a512"}},"solidity/NotaryManager.sol:AttestationHubEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"AttestationAccepted","type":"event"}],"userDoc":{"events":{"AttestationAccepted(address,bytes)":{"notice":"Emitted when an attestation is submitted to AttestationHub."}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"AttestationAccepted(address,bytes)":{"params":{"attestation":"Raw payload with attestation data and notary signature","notary":"Notary who signed the attestation"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"AttestationAccepted\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"AttestationAccepted(address,bytes)\":{\"params\":{\"attestation\":\"Raw payload with attestation data and notary signature\",\"notary\":\"Notary who signed the attestation\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"AttestationAccepted(address,bytes)\":{\"notice\":\"Emitted when an attestation is submitted to AttestationHub.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"AttestationHubEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Auth":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e84357cdd232ee0640e3b2fd532fa6b490ad496c013a7ab917638a29201799f964736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e84357cdd232ee0640e3b2fd532fa6b490ad496c013a7ab917638a29201799f964736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"76770:610:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;76770:610:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"76770:610:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Auth\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:ByteString":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122026c9f205db599a81d7c5f56adea9f247df31b9a417e5edd21bcd401466dc8e5764736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122026c9f205db599a81d7c5f56adea9f247df31b9a417e5edd21bcd401466dc8e5764736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"42490:5335:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;42490:5335:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"42490:5335:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"SELECTOR_LENGTH":{"details":"Call payload memory layout [000 .. 004) selector    bytes4  4 bytes      Optional: N function arguments [004 .. 036) arg1        bytes32 32 bytes      .. [AAA .. END) argN        bytes32 32 bytes"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"SELECTOR_LENGTH\":{\"details\":\"Call payload memory layout [000 .. 004) selector    bytes4  4 bytes      Optional: N function arguments [004 .. 036) arg1        bytes32 32 bytes      .. [AAA .. END) argN        bytes32 32 bytes\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"ByteString\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Context\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:ContextUpgradeable":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"stateVariables":{"__gap":{"details":"This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"}],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"__gap\":{\"details\":\"This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"ContextUpgradeable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:DomainContext":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"DomainContext\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"localDomain()":"8d3638f4"}},"solidity/NotaryManager.sol:DomainNotaryRegistry":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"},{"inputs":[],"name":"allNotaries","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getNotary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notariesAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"userDoc":{"events":{"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{"allNotaries()":{"notice":"Returns addresses of all Notaries."},"getNotary(uint256)":{"notice":"Returns i-th Notary. O(1)"},"notariesAmount()":{"notice":"Returns amount of active notaries. O(1)"}},"version":1},"developerDoc":{"kind":"dev","methods":{"allNotaries()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"getNotary(uint256)":{"details":"Will revert if index is out of range"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allNotaries\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getNotary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notariesAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allNotaries()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"getNotary(uint256)\":{\"details\":\"Will revert if index is out of range\"}},\"version\":1},\"userdoc\":{\"events\":{\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{\"allNotaries()\":{\"notice\":\"Returns addresses of all Notaries.\"},\"getNotary(uint256)\":{\"notice\":\"Returns i-th Notary. O(1)\"},\"notariesAmount()\":{\"notice\":\"Returns amount of active notaries. O(1)\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"DomainNotaryRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"allNotaries()":"9817e315","getNotary(uint256)":"c07dc7f5","localDomain()":"8d3638f4","notariesAmount()":"8e62e9ef"}},"solidity/NotaryManager.sol:ECDSA":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d7963f18767b2143e1217884f2665ac5f919b5e2f43e82dffeb5dc74a9d1126d64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d7963f18767b2143e1217884f2665ac5f919b5e2f43e82dffeb5dc74a9d1126d64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"68393:8375:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;68393:8375:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"68393:8375:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"ECDSA\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ce90068042255e347b78470bfdb8445436a5cc1de61c526110103f6c5cc64e5c64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ce90068042255e347b78470bfdb8445436a5cc1de61c526110103f6c5cc64e5c64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"82130:11454:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;82130:11454:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"82130:11454:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"EnumerableSet\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:GuardRegistry":{"code":"0x608060405234801561001057600080fd5b50610265806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063246c244914610046578063629ddf69146100615780639fe03fa214610099575b600080fd5b61004e6100ae565b6040519081526020015b60405180910390f35b61007461006f36600461018d565b6100bf565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610058565b6100a16100d1565b60405161005891906101a6565b60006100ba60006100dd565b905090565b60006100cb81836100e7565b92915050565b60606100ba60006100fa565b60006100cb825490565b60006100f38383610107565b9392505050565b606060006100f383610131565b600082600001828154811061011e5761011e610200565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561018157602002820191906000526020600020905b81548152602001906001019080831161016d575b50505050509050919050565b60006020828403121561019f57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156101f457835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016101c2565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea26469706673582212206c6735465468f204aa566521e0dba3b86d2632715a724dac55ddcffe9bc032e164736f6c63430008110033","runtime-code":"0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063246c244914610046578063629ddf69146100615780639fe03fa214610099575b600080fd5b61004e6100ae565b6040519081526020015b60405180910390f35b61007461006f36600461018d565b6100bf565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610058565b6100a16100d1565b60405161005891906101a6565b60006100ba60006100dd565b905090565b60006100cb81836100e7565b92915050565b60606100ba60006100fa565b60006100cb825490565b60006100f38383610107565b9392505050565b606060006100f383610131565b600082600001828154811061011e5761011e610200565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561018157602002820191906000526020600020905b81548152602001906001019080831161016d575b50505050509050919050565b60006020828403121561019f57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156101f457835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016101c2565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea26469706673582212206c6735465468f204aa566521e0dba3b86d2632715a724dac55ddcffe9bc032e164736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"102516:3425:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"102516:3425:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104481:95;;;:::i;:::-;;;160:25:1;;;148:2;133:18;104481:95:0;;;;;;;;104299:107;;;;;;:::i;:::-;;:::i;:::-;;;557:42:1;545:55;;;527:74;;515:2;500:18;104299:107:0;381:226:1;104087:101:0;;;:::i;:::-;;;;;;;:::i;104481:95::-;104528:7;104554:15;:6;:13;:15::i;:::-;104547:22;;104481:95;:::o;104299:107::-;104356:7;104382:17;104356:7;104392:6;104382:9;:17::i;:::-;104375:24;104299:107;-1:-1:-1;;104299:107:0:o;104087:101::-;104131:16;104166:15;:6;:13;:15::i;89731:115::-;89794:7;89820:19;89828:3;85346:18;;85264:107;90188:156;90262:7;90312:22;90316:3;90328:5;90312:3;:22::i;:::-;90304:31;90188:156;-1:-1:-1;;;90188:156:0:o;90884:300::-;90947:16;90975:22;91000:19;91008:3;91000:7;:19::i;85713:118::-;85780:7;85806:3;:11;;85818:5;85806:18;;;;;;;;:::i;:::-;;;;;;;;;85799:25;;85713:118;;;;:::o;86371:109::-;86427:16;86462:3;:11;;86455:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86371:109;;;:::o;196:180:1:-;255:6;308:2;296:9;287:7;283:23;279:32;276:52;;;324:1;321;314:12;276:52;-1:-1:-1;347:23:1;;196:180;-1:-1:-1;196:180:1:o;612:681::-;783:2;835:21;;;905:13;;808:18;;;927:22;;;754:4;;783:2;1006:15;;;;980:2;965:18;;;754:4;1049:218;1063:6;1060:1;1057:13;1049:218;;;1128:13;;1143:42;1124:62;1112:75;;1242:15;;;;1207:12;;;;1085:1;1078:9;1049:218;;;-1:-1:-1;1284:3:1;;612:681;-1:-1:-1;;;;;;612:681:1:o;1298:184::-;1350:77;1347:1;1340:88;1447:4;1444:1;1437:15;1471:4;1468:1;1461:15","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"},{"inputs":[],"name":"allGuards","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getGuard","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"userDoc":{"events":{"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."}},"kind":"user","methods":{"allGuards()":{"notice":"Returns addresses of all Guards."},"getGuard(uint256)":{"notice":"Returns i-th Guard. O(1)"},"guardsAmount()":{"notice":"Returns amount of active guards. O(1)"}},"version":1},"developerDoc":{"kind":"dev","methods":{"allGuards()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"getGuard(uint256)":{"details":"Will revert if index is out of range"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allGuards\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getGuard\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardsAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allGuards()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"getGuard(uint256)\":{\"details\":\"Will revert if index is out of range\"}},\"version\":1},\"userdoc\":{\"events\":{\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"}},\"kind\":\"user\",\"methods\":{\"allGuards()\":{\"notice\":\"Returns addresses of all Guards.\"},\"getGuard(uint256)\":{\"notice\":\"Returns i-th Guard. O(1)\"},\"guardsAmount()\":{\"notice\":\"Returns amount of active guards. O(1)\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"GuardRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"allGuards()":"9fe03fa2","getGuard(uint256)":"629ddf69","guardsAmount()":"246c2449"}},"solidity/NotaryManager.sol:GuardRegistryEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"}],"userDoc":{"events":{"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"GuardAdded(address)":{"params":{"guard":"Address of the added guard"}},"GuardRemoved(address)":{"params":{"guard":"Address of the removed guard"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"GuardAdded(address)\":{\"params\":{\"guard\":\"Address of the added guard\"}},\"GuardRemoved(address)\":{\"params\":{\"guard\":\"Address of the removed guard\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"GuardRegistryEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Header":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ddcf2c2c0cf9322c4096898455150151957dd626c3deb8d9f9ed2b18fe0a3a0064736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ddcf2c2c0cf9322c4096898455150151957dd626c3deb8d9f9ed2b18fe0a3a0064736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"140587:6119:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;140587:6119:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"140587:6119:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"OFFSET_VERSION":{"details":"Header memory layout [000 .. 002): version            uint16   2 bytes [002 .. 006): origin             uint32   4 bytes [006 .. 038): sender             bytes32 32 bytes [038 .. 042): nonce              uint32   4 bytes [042 .. 046): destination        uint32   4 bytes [046 .. 078): recipient          bytes32 32 bytes [078 .. 082): optimisticSeconds  uint32   4 bytes"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"OFFSET_VERSION\":{\"details\":\"Header memory layout [000 .. 002): version            uint16   2 bytes [002 .. 006): origin             uint32   4 bytes [006 .. 038): sender             bytes32 32 bytes [038 .. 042): nonce              uint32   4 bytes [042 .. 046): destination        uint32   4 bytes [046 .. 078): recipient          bytes32 32 bytes [078 .. 082): optimisticSeconds  uint32   4 bytes\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Header\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:INotaryManager":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"notary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_reporter","type":"address"}],"name":"slashNotary","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"notary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_reporter\",\"type\":\"address\"}],\"name\":\"slashNotary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"INotaryManager\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"notary()":"9d54c79d","slashNotary(address)":"bb99e8fa"}},"solidity/NotaryManager.sol:ISystemRouter":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_optimisticSeconds","type":"uint32"},{"internalType":"enum ISystemRouter.SystemEntity","name":"_recipient","type":"uint8"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"systemCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_optimisticSeconds","type":"uint32"},{"internalType":"enum ISystemRouter.SystemEntity[]","name":"_recipients","type":"uint8[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"systemMultiCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_optimisticSeconds","type":"uint32"},{"internalType":"enum ISystemRouter.SystemEntity","name":"_recipient","type":"uint8"},{"internalType":"bytes[]","name":"_dataArray","type":"bytes[]"}],"name":"systemMultiCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_optimisticSeconds","type":"uint32"},{"internalType":"enum ISystemRouter.SystemEntity[]","name":"_recipients","type":"uint8[]"},{"internalType":"bytes[]","name":"_dataArray","type":"bytes[]"}],"name":"systemMultiCall","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"systemCall(uint32,uint32,uint8,bytes)":{"notice":"Call a System Contract on the destination chain with a given data payload. Note: for system calls on the local chain - use `destination = localDomain` - `_optimisticSeconds` value will be ignored"},"systemMultiCall(uint32,uint32,uint8,bytes[])":{"notice":"Calls a single system contract a few times using the given calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none."},"systemMultiCall(uint32,uint32,uint8[],bytes)":{"notice":"Calls a few system contracts using the same calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none."},"systemMultiCall(uint32,uint32,uint8[],bytes[])":{"notice":"Calls a few system contracts using the given calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none."}},"version":1},"developerDoc":{"kind":"dev","methods":{"systemCall(uint32,uint32,uint8,bytes)":{"details":"Only System contracts are allowed to call this function. Note: knowledge of recipient address is not required, routing will be done by SystemRouter on the destination chain. Following call will be made on destination chain: - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt) This allows recipient to check: - callOrigin: domain where a system call originated (local domain in this case) - systemCaller: system entity who initiated the call (msg.sender on local chain) - rootSubmittedAt:   - For cross-chain calls: timestamp when merkle root (used for executing the system call)     was submitted to destination and its optimistic timer started ticking   - For on-chain calls: timestamp of the current block","params":{"_data":"Data for calling recipient on destination chain","_destination":"Domain of destination chain","_optimisticSeconds":"Optimistic period for the message","_recipient":"System entity to receive the call on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_optimisticSeconds\",\"type\":\"uint32\"},{\"internalType\":\"enum ISystemRouter.SystemEntity\",\"name\":\"_recipient\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"systemCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_optimisticSeconds\",\"type\":\"uint32\"},{\"internalType\":\"enum ISystemRouter.SystemEntity[]\",\"name\":\"_recipients\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"systemMultiCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_optimisticSeconds\",\"type\":\"uint32\"},{\"internalType\":\"enum ISystemRouter.SystemEntity\",\"name\":\"_recipient\",\"type\":\"uint8\"},{\"internalType\":\"bytes[]\",\"name\":\"_dataArray\",\"type\":\"bytes[]\"}],\"name\":\"systemMultiCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_optimisticSeconds\",\"type\":\"uint32\"},{\"internalType\":\"enum ISystemRouter.SystemEntity[]\",\"name\":\"_recipients\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes[]\",\"name\":\"_dataArray\",\"type\":\"bytes[]\"}],\"name\":\"systemMultiCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"systemCall(uint32,uint32,uint8,bytes)\":{\"details\":\"Only System contracts are allowed to call this function. Note: knowledge of recipient address is not required, routing will be done by SystemRouter on the destination chain. Following call will be made on destination chain: - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt) This allows recipient to check: - callOrigin: domain where a system call originated (local domain in this case) - systemCaller: system entity who initiated the call (msg.sender on local chain) - rootSubmittedAt:   - For cross-chain calls: timestamp when merkle root (used for executing the system call)     was submitted to destination and its optimistic timer started ticking   - For on-chain calls: timestamp of the current block\",\"params\":{\"_data\":\"Data for calling recipient on destination chain\",\"_destination\":\"Domain of destination chain\",\"_optimisticSeconds\":\"Optimistic period for the message\",\"_recipient\":\"System entity to receive the call on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"systemCall(uint32,uint32,uint8,bytes)\":{\"notice\":\"Call a System Contract on the destination chain with a given data payload. Note: for system calls on the local chain - use `destination = localDomain` - `_optimisticSeconds` value will be ignored\"},\"systemMultiCall(uint32,uint32,uint8,bytes[])\":{\"notice\":\"Calls a single system contract a few times using the given calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none.\"},\"systemMultiCall(uint32,uint32,uint8[],bytes)\":{\"notice\":\"Calls a few system contracts using the same calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none.\"},\"systemMultiCall(uint32,uint32,uint8[],bytes[])\":{\"notice\":\"Calls a few system contracts using the given calldata for each call. See `systemCall` for details on system calls. Note: tx will revert if any of the calls revert, guaranteeing that either all calls succeed or none.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"ISystemRouter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"systemCall(uint32,uint32,uint8,bytes)":"bf65bc46","systemMultiCall(uint32,uint32,uint8,bytes[])":"4491b24d","systemMultiCall(uint32,uint32,uint8[],bytes)":"2ec0b338","systemMultiCall(uint32,uint32,uint8[],bytes[])":"de58387b"}},"solidity/NotaryManager.sol:Initializable":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"custom:oz-upgrades-unsafe-allow":"constructor constructor() {     _disableInitializers(); } ``` ====","details":"This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. The initialization functions use a version number. Once a version number is used, it is consumed and cannot be reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in case an upgrade adds a module that needs to be initialized. For example: [.hljs-theme-light.nopadding] ``` contract MyToken is ERC20Upgradeable {     function initialize() initializer public {         __ERC20_init(\"MyToken\", \"MTK\");     } } contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {     function initializeV2() reinitializer(2) public {         __ERC20Permit_init(\"MyToken\");     } } ``` TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. [CAUTION] ==== Avoid leaving a contract uninitialized. An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: [.hljs-theme-light.nopadding] ```","events":{"Initialized(uint8)":{"details":"Triggered when the contract has been initialized or reinitialized."}},"kind":"dev","methods":{},"stateVariables":{"_initialized":{"custom:oz-retyped-from":"bool","details":"Indicates that the contract has been initialized."},"_initializing":{"details":"Indicates that the contract is in the process of being initialized."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"}],\"devdoc\":{\"custom:oz-upgrades-unsafe-allow\":\"constructor constructor() {     _disableInitializers(); } ``` ====\",\"details\":\"This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. The initialization functions use a version number. Once a version number is used, it is consumed and cannot be reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in case an upgrade adds a module that needs to be initialized. For example: [.hljs-theme-light.nopadding] ``` contract MyToken is ERC20Upgradeable {     function initialize() initializer public {         __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");     } } contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {     function initializeV2() reinitializer(2) public {         __ERC20Permit_init(\\\"MyToken\\\");     } } ``` TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. [CAUTION] ==== Avoid leaving a contract uninitialized. An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: [.hljs-theme-light.nopadding] ```\",\"events\":{\"Initialized(uint8)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"}},\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"_initialized\":{\"custom:oz-retyped-from\":\"bool\",\"details\":\"Indicates that the contract has been initialized.\"},\"_initializing\":{\"details\":\"Indicates that the contract is in the process of being initialized.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Initializable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:LocalDomainContext":{"code":"0x60a060405234801561001057600080fd5b5060405161011f38038061011f83398101604081905261002f9161003d565b63ffffffff1660805261006a565b60006020828403121561004f57600080fd5b815163ffffffff8116811461006357600080fd5b9392505050565b608051609d6100826000396000602f0152609d6000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80638d3638f414602d575b600080fd5b7f000000000000000000000000000000000000000000000000000000000000000060405163ffffffff909116815260200160405180910390f3fea2646970667358221220a5d99acddc2dfe438f8a780361e95b34a0737a6ad364c7329583734b4672772464736f6c63430008110033","runtime-code":"0x6080604052348015600f57600080fd5b506004361060285760003560e01c80638d3638f414602d575b600080fd5b7f000000000000000000000000000000000000000000000000000000000000000060405163ffffffff909116815260200160405180910390f3fea2646970667358221220a5d99acddc2dfe438f8a780361e95b34a0737a6ad364c7329583734b4672772464736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"581:283:0:-:0;;;677:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;720:28;;;;581:283;;14:280:1;83:6;136:2;124:9;115:7;111:23;107:32;104:52;;;152:1;149;142:12;104:52;184:9;178:16;234:10;227:5;223:22;216:5;213:33;203:61;;260:1;257;250:12;203:61;283:5;14:280;-1:-1:-1;;;14:280:1:o;:::-;581:283:0;;;;;;;;;;;;","srcMapRuntime":"581:283:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;416:92;842:13;416:92;;188:10:1;176:23;;;158:42;;146:2;131:18;416:92:0;;;;;;","abiDefinition":[{"inputs":[{"internalType":"uint32","name":"localDomain_","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"localDomain_\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"LocalDomainContext\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"localDomain()":"8d3638f4"}},"solidity/NotaryManager.sol:MerkleLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200c019d6c60043bfd91066988d04dc904e529295a90309f8c25fb9d6154bd320d64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200c019d6c60043bfd91066988d04dc904e529295a90309f8c25fb9d6154bd320d64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"113133:8429:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;113133:8429:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"113133:8429:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"MerkleLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Message":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f5ee93bbb960fe94ff1b8446392843bea3c7d24a7e502010851fd3da8293c01264736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f5ee93bbb960fe94ff1b8446392843bea3c7d24a7e502010851fd3da8293c01264736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"152213:8258:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;152213:8258:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"152213:8258:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"MESSAGE_VERSION":{"details":"This is only updated if the whole message structure is changed,      i.e. if a new part is added.      If already existing part is changed, the message version does not get bumped."},"OFFSET_HEADER":{"details":"This value reflects the header offset in the latest message version"},"OFFSET_VERSION":{"details":"Message memory layout [000 .. 002): version            uint16  2 bytes [002 .. 004): header length      uint16  2 bytes (length == AAA - 6) [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA) [006 .. AAA): header             bytes   ? bytes [AAA .. BBB): tips               bytes   ? bytes [BBB .. CCC): body               bytes   ? bytes (length could be zero)"},"TWO_BYTES":{"details":"How much bytes is used for storing the version, or a single offset value"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"MESSAGE_VERSION\":{\"details\":\"This is only updated if the whole message structure is changed,      i.e. if a new part is added.      If already existing part is changed, the message version does not get bumped.\"},\"OFFSET_HEADER\":{\"details\":\"This value reflects the header offset in the latest message version\"},\"OFFSET_VERSION\":{\"details\":\"Message memory layout [000 .. 002): version            uint16  2 bytes [002 .. 004): header length      uint16  2 bytes (length == AAA - 6) [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA) [006 .. AAA): header             bytes   ? bytes [AAA .. BBB): tips               bytes   ? bytes [BBB .. CCC): body               bytes   ? bytes (length could be zero)\"},\"TWO_BYTES\":{\"details\":\"How much bytes is used for storing the version, or a single offset value\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Message\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:NotaryManager":{"code":"0x6080604052604051610745380380610745833981016040819052610022916100a0565b61002b33610050565b600280546001600160a01b0319166001600160a01b03929092169190911790556100d0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156100b257600080fd5b81516001600160a01b03811681146100c957600080fd5b9392505050565b610666806100df6000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80639d54c79d1161005b5780639d54c79d1461010d578063a394a0e61461012b578063bb99e8fa1461013e578063f2fde38b1461015157600080fd5b806347c484e91461008d578063715018a6146100a25780638da5cb5b146100aa578063938b5f32146100ed575b600080fd5b6100a061009b36600461060c565b610164565b005b6100a0610269565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001546100c49073ffffffffffffffffffffffffffffffffffffffff1681565b60025473ffffffffffffffffffffffffffffffffffffffff166100c4565b6100a061013936600461060c565b610273565b6100a061014c36600461060c565b610376565b6100a061015f36600461060c565b61043d565b61016c6104f4565b73ffffffffffffffffffffffffffffffffffffffff81163b6101ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f21636f6e7472616374206f726967696e0000000000000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd3b105cfc67ac2f6990a1958e63212ca65ce6facf20a6fce372b6b58afd4098d906020015b60405180910390a150565b6102716104f4565b565b61027b6104f4565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556001546040517fa394a0e600000000000000000000000000000000000000000000000000000000815260048101929092529091169063a394a0e690602401600060405180830381600087803b15801561031757600080fd5b505af115801561032b573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff841681527fe2bea979965a228cbde9e65befc96655827ad8934c3c6b9f8b9b66e1f907ef889250602001905061025e565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f216f726967696e0000000000000000000000000000000000000000000000000060448201526064016101e6565b60405173ffffffffffffffffffffffffffffffffffffffff821681527f4180932f5f5f11458bcd408e42c54626987799e7c4c89f40f484fefdfdfff14f9060200161025e565b6104456104f4565b73ffffffffffffffffffffffffffffffffffffffff81166104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101e6565b6104f181610575565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610271576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101e6565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146104f157600080fd5b60006020828403121561061e57600080fd5b8135610629816105ea565b939250505056fea2646970667358221220251d51413c500ff1efcd3f938d171b751f5970bc55235539a7bc7c86ef90b34164736f6c63430008110033","runtime-code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c80639d54c79d1161005b5780639d54c79d1461010d578063a394a0e61461012b578063bb99e8fa1461013e578063f2fde38b1461015157600080fd5b806347c484e91461008d578063715018a6146100a25780638da5cb5b146100aa578063938b5f32146100ed575b600080fd5b6100a061009b36600461060c565b610164565b005b6100a0610269565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001546100c49073ffffffffffffffffffffffffffffffffffffffff1681565b60025473ffffffffffffffffffffffffffffffffffffffff166100c4565b6100a061013936600461060c565b610273565b6100a061014c36600461060c565b610376565b6100a061015f36600461060c565b61043d565b61016c6104f4565b73ffffffffffffffffffffffffffffffffffffffff81163b6101ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f21636f6e7472616374206f726967696e0000000000000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd3b105cfc67ac2f6990a1958e63212ca65ce6facf20a6fce372b6b58afd4098d906020015b60405180910390a150565b6102716104f4565b565b61027b6104f4565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556001546040517fa394a0e600000000000000000000000000000000000000000000000000000000815260048101929092529091169063a394a0e690602401600060405180830381600087803b15801561031757600080fd5b505af115801561032b573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff841681527fe2bea979965a228cbde9e65befc96655827ad8934c3c6b9f8b9b66e1f907ef889250602001905061025e565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f216f726967696e0000000000000000000000000000000000000000000000000060448201526064016101e6565b60405173ffffffffffffffffffffffffffffffffffffffff821681527f4180932f5f5f11458bcd408e42c54626987799e7c4c89f40f484fefdfdfff14f9060200161025e565b6104456104f4565b73ffffffffffffffffffffffffffffffffffffffff81166104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101e6565b6104f181610575565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610271576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101e6565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146104f157600080fd5b60006020828403121561061e57600080fd5b8135610629816105ea565b939250505056fea2646970667358221220251d51413c500ff1efcd3f938d171b751f5970bc55235539a7bc7c86ef90b34164736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"220735:2375:0:-:0;;;221323:95;;;;;;;;;;;;;;;;;;:::i;:::-;218765:32;218357:10;218765:18;:32::i;:::-;221387:7:::1;:24:::0;;-1:-1:-1;;;;;;221387:24:0::1;-1:-1:-1::0;;;;;221387:24:0;;;::::1;::::0;;;::::1;::::0;;220735:2375;;220262:187;220335:16;220354:6;;-1:-1:-1;;;;;220370:17:0;;;-1:-1:-1;;;;;;220370:17:0;;;;;;220402:40;;220354:6;;;;;;;220402:40;;220335:16;220402:40;220325:124;220262:187;:::o;14:290:1:-;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:1:o;:::-;220735:2375:0;;;;;;","srcMapRuntime":"220735:2375:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;221657:188;;;;;;:::i;:::-;;:::i;:::-;;223024:84;;;:::i;219030:85::-;219076:7;219102:6;;;219030:85;;;601:42:1;589:55;;;571:74;;559:2;544:18;219030:85:0;;;;;;;220895:21;;;;;;;;;222705:90;222781:7;;;;222705:90;;222016:193;;;;;;:::i;:::-;;:::i;222483:121::-;;;;;;:::i;:::-;;:::i;219910:198::-;;;;;;:::i;:::-;;:::i;221657:188::-;218923:13;:11;:13::i;:::-;198442:19;;;;221722:56:::1;;;::::0;::::1;::::0;;1118:2:1;221722:56:0::1;::::0;::::1;1100:21:1::0;1157:2;1137:18;;;1130:30;1196:18;1176;;;1169:46;1232:18;;221722:56:0::1;;;;;;;;;221788:6;:16:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;221820:18:::1;::::0;571:74:1;;;221820:18:0::1;::::0;559:2:1;544:18;221820::0::1;;;;;;;;221657:188:::0;:::o;223024:84::-;218923:13;:11;:13::i;:::-;223024:84::o;222016:193::-;218923:13;:11;:13::i;:::-;222088:7:::1;:24:::0;;;::::1;;::::0;;::::1;::::0;;::::1;::::0;;;-1:-1:-1;222129:6:0;222122:40:::1;::::0;;;;::::1;::::0;::::1;571:74:1::0;;;;222129:6:0;;::::1;::::0;222122:24:::1;::::0;544:18:1;;222122:40:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;222177:25:0::1;::::0;601:42:1;589:55;;571:74;;222177:25:0::1;::::0;-1:-1:-1;559:2:1;544:18;;-1:-1:-1;222177:25:0::1;425:226:1::0;222483:121:0;221235:6;;;;221221:10;:20;221213:40;;;;;;;1463:2:1;221213:40:0;;;1445:21:1;1502:1;1482:18;;;1475:29;1540:9;1520:18;;;1513:37;1567:18;;221213:40:0;1261:330:1;221213:40:0;222575:22:::1;::::0;601:42:1;589:55;;571:74;;222575:22:0::1;::::0;559:2:1;544:18;222575:22:0::1;425:226:1::0;219910:198:0;218923:13;:11;:13::i;:::-;219998:22:::1;::::0;::::1;219990:73;;;::::0;::::1;::::0;;2037:2:1;219990:73:0::1;::::0;::::1;2019:21:1::0;2076:2;2056:18;;;2049:30;2115:34;2095:18;;;2088:62;2186:8;2166:18;;;2159:36;2212:19;;219990:73:0::1;1835:402:1::0;219990:73:0::1;220073:28;220092:8;220073:18;:28::i;:::-;219910:198:::0;:::o;219188:130::-;219076:7;219102:6;219251:23;219102:6;218357:10;219251:23;219243:68;;;;;;;2444:2:1;219243:68:0;;;2426:21:1;;;2463:18;;;2456:30;2522:34;2502:18;;;2495:62;2574:18;;219243:68:0;2242:356:1;220262:187:0;220335:16;220354:6;;;220370:17;;;;;;;;;;220402:40;;220354:6;;;;;;;220402:40;;220335:16;220402:40;220325:124;220262:187;:::o;14:154:1:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:247;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;:::-;409:5;173:247;-1:-1:-1;;;173:247:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_notaryAddress","type":"address"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reporter","type":"address"}],"name":"FakeSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NewNotary","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"origin","type":"address"}],"name":"NewOrigin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"notary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"origin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_notaryAddress","type":"address"}],"name":"setNotary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_origin","type":"address"}],"name":"setOrigin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_reporter","type":"address"}],"name":"slashNotary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"events":{"FakeSlashed(address)":{"notice":"Emitted when slashNotary is called"},"NewNotary(address)":{"notice":"Emitted when a new notary is set"},"NewOrigin(address)":{"notice":"Emitted when a new origin is set"}},"kind":"user","methods":{"notary()":{"notice":"Get address of current notary"},"setNotary(address)":{"notice":"Set the address of a new notary"},"setOrigin(address)":{"notice":"Set the address of the a new origin contract"},"slashNotary(address)":{"notice":"Slashes the notary"}},"notice":"MVP / centralized version of contract that will manage Notary bonding, slashing, selection and rotation","version":1},"developerDoc":{"author":"Illusory Systems Inc.","kind":"dev","methods":{"notary()":{"returns":{"_0":"the notary address"}},"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"should be impossible to renounce ownership; we override OpenZeppelin Ownable implementation of renounceOwnership to make it a no-op"},"setNotary(address)":{"details":"only callable by trusted owner","params":{"_notaryAddress":"The address of the new notary"}},"setOrigin(address)":{"details":"only callable by trusted owner","params":{"_origin":"The address of the new origin contract"}},"slashNotary(address)":{"details":"Currently does nothing, functionality will be implemented later when notary bonding and rotation are also implemented","params":{"_reporter":"The address of the entity that reported the notary fraud"}},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"title":"NotaryManager","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_notaryAddress\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"FakeSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NewNotary\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"origin\",\"type\":\"address\"}],\"name\":\"NewOrigin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"notary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"origin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_notaryAddress\",\"type\":\"address\"}],\"name\":\"setNotary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_origin\",\"type\":\"address\"}],\"name\":\"setOrigin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_reporter\",\"type\":\"address\"}],\"name\":\"slashNotary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Illusory Systems Inc.\",\"kind\":\"dev\",\"methods\":{\"notary()\":{\"returns\":{\"_0\":\"the notary address\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"should be impossible to renounce ownership; we override OpenZeppelin Ownable implementation of renounceOwnership to make it a no-op\"},\"setNotary(address)\":{\"details\":\"only callable by trusted owner\",\"params\":{\"_notaryAddress\":\"The address of the new notary\"}},\"setOrigin(address)\":{\"details\":\"only callable by trusted owner\",\"params\":{\"_origin\":\"The address of the new origin contract\"}},\"slashNotary(address)\":{\"details\":\"Currently does nothing, functionality will be implemented later when notary bonding and rotation are also implemented\",\"params\":{\"_reporter\":\"The address of the entity that reported the notary fraud\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"NotaryManager\",\"version\":1},\"userdoc\":{\"events\":{\"FakeSlashed(address)\":{\"notice\":\"Emitted when slashNotary is called\"},\"NewNotary(address)\":{\"notice\":\"Emitted when a new notary is set\"},\"NewOrigin(address)\":{\"notice\":\"Emitted when a new origin is set\"}},\"kind\":\"user\",\"methods\":{\"notary()\":{\"notice\":\"Get address of current notary\"},\"setNotary(address)\":{\"notice\":\"Set the address of a new notary\"},\"setOrigin(address)\":{\"notice\":\"Set the address of the a new origin contract\"},\"slashNotary(address)\":{\"notice\":\"Slashes the notary\"}},\"notice\":\"MVP / centralized version of contract that will manage Notary bonding, slashing, selection and rotation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"NotaryManager\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"notary()":"9d54c79d","origin()":"938b5f32","owner()":"8da5cb5b","renounceOwnership()":"715018a6","setNotary(address)":"a394a0e6","setOrigin(address)":"47c484e9","slashNotary(address)":"bb99e8fa","transferOwnership(address)":"f2fde38b"}},"solidity/NotaryManager.sol:NotaryManagerEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reporter","type":"address"}],"name":"FakeSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NewNotary","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"origin","type":"address"}],"name":"NewOrigin","type":"event"}],"userDoc":{"events":{"FakeSlashed(address)":{"notice":"Emitted when slashNotary is called"},"NewNotary(address)":{"notice":"Emitted when a new notary is set"},"NewOrigin(address)":{"notice":"Emitted when a new origin is set"}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"NewNotary(address)":{"params":{"notary":"The address of the new notary"}},"NewOrigin(address)":{"params":{"origin":"The address of the new origin contract"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"FakeSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NewNotary\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"origin\",\"type\":\"address\"}],\"name\":\"NewOrigin\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"NewNotary(address)\":{\"params\":{\"notary\":\"The address of the new notary\"}},\"NewOrigin(address)\":{\"params\":{\"origin\":\"The address of the new origin contract\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"FakeSlashed(address)\":{\"notice\":\"Emitted when slashNotary is called\"},\"NewNotary(address)\":{\"notice\":\"Emitted when a new notary is set\"},\"NewOrigin(address)\":{\"notice\":\"Emitted when a new origin is set\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"NotaryManagerEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:NotaryRegistryEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"}],"userDoc":{"events":{"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"NotaryRemoved(uint32,address)":{"params":{"domain":"Domain where a Notary was removed","notary":"Address of the removed notary"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"NotaryRemoved(uint32,address)\":{\"params\":{\"domain\":\"Domain where a Notary was removed\",\"notary\":\"Address of the removed notary\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"NotaryRegistryEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Origin":{"code":"0x60a06040523480156200001157600080fd5b506040516200425138038062004251833981016040819052620000349162000043565b63ffffffff1660805262000072565b6000602082840312156200005657600080fd5b815163ffffffff811681146200006b57600080fd5b9392505050565b60805161418b620000c6600039600081816102e101528181610bd0015281816112b501528181611393015281816114d60152818161187701528181611f2601528181613249015261365e015261418b6000f3fe6080604052600436106101a15760003560e01c8063a394a0e6116100e1578063f2fde38b1161008a578063f85b597e11610064578063f85b597e146104c1578063f94adcb4146104ee578063fbde22f714610529578063ffa1ad741461054957600080fd5b8063f2fde38b1461046e578063f646a5121461048e578063f7560e40146104ae57600080fd5b8063c4d66de8116100bb578063c4d66de8146103f2578063dd0f1f7414610412578063e65b6bd41461044e57600080fd5b8063a394a0e61461039c578063bf61e67e146103bc578063c07dc7f5146103d257600080fd5b8063715018a61161014e5780638e62e9ef116101285780638e62e9ef146103305780639817e315146103455780639fe03fa214610367578063a340abc11461037c57600080fd5b8063715018a6146102bb5780638d3638f4146102d25780638da5cb5b1461030557600080fd5b8063529d15491161017f578063529d1549146102195780635815869d1461026b578063629ddf691461029b57600080fd5b8063141c4985146101a6578063246c2449146101e0578063522ae00214610203575b600080fd5b3480156101b257600080fd5b506101c66101c1366004613971565b610570565b60405163ffffffff90911681526020015b60405180910390f35b3480156101ec57600080fd5b506101f5610581565b6040519081526020016101d7565b34801561020f57600080fd5b506101f561080081565b34801561022557600080fd5b506065546102469073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d7565b34801561027757600080fd5b5061028b610286366004613a66565b610592565b60405190151581526020016101d7565b3480156102a757600080fd5b506102466102b6366004613a9b565b6105db565b3480156102c757600080fd5b506102d06105e8565b005b3480156102de57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006101c6565b34801561031157600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610246565b34801561033c57600080fd5b506101f5610656565b34801561035157600080fd5b5061035a610662565b6040516101d79190613ab4565b34801561037357600080fd5b5061035a61066e565b34801561038857600080fd5b506102d0610397366004613b30565b61067a565b3480156103a857600080fd5b506102d06103b7366004613b30565b6106ed565b3480156103c857600080fd5b506101c66110ad81565b3480156103de57600080fd5b506102466103ed366004613a9b565b610761565b3480156103fe57600080fd5b506102d061040d366004613b30565b61076e565b34801561041e57600080fd5b5061043261042d366004613971565b6108c1565b6040805163ffffffff90931683526020830191909152016101d7565b34801561045a57600080fd5b506101f5610469366004613971565b6108e9565b34801561047a57600080fd5b506102d0610489366004613b30565b610915565b34801561049a57600080fd5b5061028b6104a9366004613a66565b610a0e565b6104326104bc366004613b4d565b610a33565b3480156104cd57600080fd5b5060ff546102469073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104fa57600080fd5b5061050e610509366004613bdc565b610c6d565b604080519384526020840192909252908201526060016101d7565b34801561053557600080fd5b506102d0610544366004613b30565b610dfb565b34801561055557600080fd5b5061055e600081565b60405160ff90911681526020016101d7565b600061057b82610ea9565b92915050565b600061058d6099610eef565b905090565b60008060006105a084610ef9565b9150915060006105b58262ffffff1916610ff2565b905060006105c282611039565b90506105d1848284868a611125565b9695505050505050565b600061057b6099836113c3565b60335473ffffffffffffffffffffffffffffffffffffffff1633146106545760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b565b600061058d6066610eef565b606061058d60666113d6565b606061058d60996113d6565b60335473ffffffffffffffffffffffffffffffffffffffff1633146106e15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b6106ea816113e3565b50565b60ff5473ffffffffffffffffffffffffffffffffffffffff1633146107545760405162461bcd60e51b815260206004820152600e60248201527f216e6f746172794d616e61676572000000000000000000000000000000000000604482015260640161064b565b61075d816114c0565b5050565b600061057b6066836113c3565b600061077a6001611558565b905080156107af57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6107b76116aa565b6107c0826113e3565b60ff54604080517f9d54c79d000000000000000000000000000000000000000000000000000000008152905161085a9273ffffffffffffffffffffffffffffffffffffffff1691639d54c79d9160048083019260209291908290030181865afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108559190613c0f565b6114c0565b50801561075d57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6000806108cd83610570565b91506000806108dc8585610c6d565b5094969095509350505050565b600061057b6108f783610ea9565b63ffffffff808516600090815260cc60205260409020919061172f16565b60335473ffffffffffffffffffffffffffffffffffffffff16331461097c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b73ffffffffffffffffffffffffffffffffffffffff8116610a055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161064b565b6106ea81611743565b6000806000610a1c846117ba565b91509150610a2b8282866117d8565b949350505050565b600080610a3e610656565b600003610a8d5760405162461bcd60e51b815260206004820152600960248201527f216e6f7461726965730000000000000000000000000000000000000000000000604482015260640161064b565b61080083511115610ae05760405162461bcd60e51b815260206004820152600c60248201527f6d736720746f6f206c6f6e670000000000000000000000000000000000000000604482015260640161064b565b6000610aeb856118a8565b9050610afc62ffffff1982166118b9565b610b485760405162461bcd60e51b815260206004820152601160248201527f21746970733a20666f726d617474696e67000000000000000000000000000000604482015260640161064b565b34610b5862ffffff198316611900565b6bffffffffffffffffffffffff1614610bb35760405162461bcd60e51b815260206004820152601060248201527f21746970733a20746f74616c5469707300000000000000000000000000000000604482015260640161064b565b610bbc88610570565b610bc7906001613c5b565b92506000610c037f0000000000000000000000000000000000000000000000000000000000000000610bf88a611944565b868c8c8c8c8c6119a3565b8051602082012093509050610c19898585611a51565b8863ffffffff168463ffffffff16847fada9f9f4bf16282091ddc28e7d70838404cd5bdff1b87d8650339e8d02b7753d8985604051610c59929190613ce6565b60405180910390a450509550959350505050565b63ffffffff8216600090815260cd60205260408120548190819015610d765763ffffffff808616600090815260cd602052604090205490851610610cf35760405162461bcd60e51b815260206004820152601c60248201527f216e6f6e63653a206578697374696e672064657374696e6174696f6e00000000604482015260640161064b565b63ffffffff808616600090815260cd60205260409020805490918616908110610d1e57610d1e613d0b565b906000526020600020015460ce60008763ffffffff1663ffffffff1681526020019081526020016000208563ffffffff1681548110610d5f57610d5f613d0b565b906000526020600020015443925092509250610df4565b63ffffffff841615610dca5760405162461bcd60e51b815260206004820152601b60248201527f216e6f6e63653a20756e6b6e6f776e2064657374696e6174696f6e0000000000604482015260640161064b565b507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757915060009050435b9250925092565b60335473ffffffffffffffffffffffffffffffffffffffff163314610e625760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b63ffffffff8116600090815260cd60205260408120548103610ecd57506000919050565b63ffffffff8216600090815260cd602052604090205461057b90600190613d3a565b600061057b825490565b600080610f0583611b11565b9050610f1662ffffff198216611b22565b610f625760405162461bcd60e51b815260206004820152600c60248201527f4e6f742061207265706f72740000000000000000000000000000000000000000604482015260640161064b565b610f96610f7462ffffff198316611b91565b610f91610f8662ffffff198516611bcf565b62ffffff1916611c1a565b611c6d565b9150610fa182611ce4565b610fed5760405162461bcd60e51b815260206004820152601560248201527f5369676e6572206973206e6f7420612067756172640000000000000000000000604482015260640161064b565b915091565b60008161100a62ffffff198216640201000000611cf1565b50611030600161101c602c6041613d4d565b62ffffff1986169190640101000000611df1565b91505b50919050565b600061104a62ffffff198316611e5c565b6110965760405162461bcd60e51b815260206004820152601260248201527f4e6f7420616e206174746573746174696f6e0000000000000000000000000000604482015260640161064b565b6110ba6110a862ffffff198416611e92565b610f91610f8662ffffff198616611ec4565b90506110d46110ce62ffffff198416611ef5565b82611f21565b6111205760405162461bcd60e51b815260206004820152601660248201527f5369676e6572206973206e6f742061206e6f7461727900000000000000000000604482015260640161064b565b919050565b60008061113762ffffff198616611faf565b9050600061114a62ffffff198716611fda565b9050600061115d62ffffff198816612006565b905061116a838383612032565b156111f25761117e62ffffff1987166120ca565b156111e6578873ffffffffffffffffffffffffffffffffffffffff167f36670329f075c374c3847f464e4acdaa51fc70c69c52cb8317787b237088ec63866040516111c99190613d60565b60405180910390a26111da896120fa565b600093505050506113ba565b600193505050506113ba565b61120162ffffff1987166120ca565b156112db578873ffffffffffffffffffffffffffffffffffffffff167fa0248f358d0f7bb4c63d2bd5a3e521bb7aba00ccfde9442154e4950711a912f88660405161124c9190613d60565b60405180910390a273ffffffffffffffffffffffffffffffffffffffff88167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e478942361129b62ffffff198a16611c1a565b6040516112a89190613d60565b60405180910390a26111e67f0000000000000000000000000000000000000000000000000000000000000000898b61214a565b8873ffffffffffffffffffffffffffffffffffffffff167f36670329f075c374c3847f464e4acdaa51fc70c69c52cb8317787b237088ec63866040516113219190613d60565b60405180910390a2611332896120fa565b73ffffffffffffffffffffffffffffffffffffffff88167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e478942361137962ffffff198a16611c1a565b6040516113869190613d60565b60405180910390a26111da7f000000000000000000000000000000000000000000000000000000000000000089600061214a565b95945050505050565b60006113cf8383612224565b9392505050565b606060006113cf8361224e565b73ffffffffffffffffffffffffffffffffffffffff81163b6114475760405162461bcd60e51b815260206004820152601760248201527f21636f6e7472616374206e6f746172794d616e61676572000000000000000000604482015260640161064b565b60ff80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe3befd3a32a53f50ff7d1421555fbd40e5ead3a7ed75417db43a23faffe093169060200160405180910390a150565b60006114cb826122aa565b1590508015611120577f00000000000000000000000000000000000000000000000000000000000000006115006066846122b7565b5060405173ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff8216907f62d8d15324cce2626119bb61d595f59e655486b1ab41b52c0793d814fe03c355906020015b60405180910390a2611033565b60008054610100900460ff16156115f5578160ff16600114801561157b5750303b155b6115ed5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161064b565b506000919050565b60005460ff8084169116106116725760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161064b565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff92909216919091179055600190565b600054610100900460ff166117275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161064b565b6106546122d9565b60006113cf838361173e61235f565b612820565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806117c6836128dd565b90506117d181611039565b9150915091565b6000806117ea62ffffff198516611faf565b905060006117fd62ffffff198616611fda565b9050600061181062ffffff198716612006565b905061181d838383612032565b93508361189e578673ffffffffffffffffffffffffffffffffffffffff167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e47894238660405161186a9190613d60565b60405180910390a261189e7f000000000000000000000000000000000000000000000000000000000000000088600061214a565b5050509392505050565b600061057b826403010200006128ea565b6000601882901c6bffffffffffffffffffffffff1660028110156118e05750600092915050565b60016118eb84612905565b61ffff16148015611030575060321492915050565b600061190b82612931565b6119148361295d565b61191d84612989565b611926856129b5565b6119309190613d73565b61193a9190613d73565b61057b9190613d73565b60007fffffffffffffffffffffffff00000000000000000000000000000000000000008214611974573392915050565b61197c6129e1565b507fffffffffffffffffffffffff0000000000000000000000000000000000000000919050565b604080517e0100000000000000000000000000000000000000000000000000000000000060208201527fffffffff0000000000000000000000000000000000000000000000000000000060e08b811b82166022840152602683018b905289811b8216604684015288811b8216604a840152604e830188905286901b16606e820152815180820360520181526072909101909152606090611a44908484612a48565b9998505050505050505050565b63ffffffff8316600090815260cd60205260408120549003611a7657611a7683612a7f565b63ffffffff838116600090815260cc60205260409020611a9c91808516908490612b0616565b63ffffffff808416600090815260cd6020908152604080832060cc9092529091209091611ace91908581169061172f16565b815460018181018455600093845260208085209092019290925563ffffffff909516825260ce855260408220805491820181558252939020439301929092555050565b600061057b826402010000006128ea565b6000601882901c6bffffffffffffffffffffffff16611b43602c6001613d4d565b611b4e906082613d4d565b8114611b5d5750600092915050565b6001611b6884612c1a565b60ff161115611b7a5750600092915050565b611030611b8684610ff2565b62ffffff1916611e5c565b600081611ba962ffffff198216640201000000611cf1565b506110306000611bbb602c6001613d4d565b62ffffff1986169190640201010000611df1565b600081611be762ffffff198216640201000000611cf1565b506000611bf6602c6041613d4d565b611c01906001613d4d565b9050610a2b62ffffff1985168260416301000000611df1565b6060600080611c378460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff1690506040519150819250611c5c8483602001612c2e565b508181016020016040529052919050565b600080611c7f62ffffff198516612dc7565b9050611cd8816040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050610a2b8184612e15565b600061057b609983612e31565b6000611cfd8383612e60565b611dea576000611d1b611d0f85612e82565b64ffffffffff16612ea6565b9150506000611d308464ffffffffff16612ea6565b6040517f5479706520617373657274696f6e206661696c65642e20476f7420307800000060208201527fffffffffffffffffffff0000000000000000000000000000000000000000000060b086811b8216603d8401527f2e20457870656374656420307800000000000000000000000000000000000000604784015283901b16605482015290925060009150605e0160405160208183030381529060405290508060405162461bcd60e51b815260040161064b9190613d60565b5090919050565b600080611dfd86612f90565b6bffffffffffffffffffffffff169050611e1686612fb7565b84611e218784613d4d565b611e2b9190613d4d565b1115611e3e5762ffffff19915050610a2b565b611e488582613d4d565b90506105d18364ffffffffff168286612ff0565b6000611e6a602c6041613d4d565b6bffffffffffffffffffffffff601884901c166bffffffffffffffffffffffff161492915050565b600081611eaa62ffffff198216640101000000611cf1565b5061103062ffffff1984166000602c640101010000611df1565b600081611edc62ffffff198216640101000000611cf1565b5061103062ffffff198416602c60416301000000611df1565b600081611f0d62ffffff198216640101000000611cf1565b5061103062ffffff19841660006004613037565b6000827f000000000000000000000000000000000000000000000000000000000000000063ffffffff168163ffffffff1614611f9f5760405162461bcd60e51b815260206004820152600c60248201527f216c6f63616c446f6d61696e0000000000000000000000000000000000000000604482015260640161064b565b610a2b836122aa565b5092915050565b600081611fc762ffffff198216640101000000611cf1565b5061103062ffffff198416600480613037565b600081611ff262ffffff198216640101000000611cf1565b5061103062ffffff19841660086004613037565b60008161201e62ffffff198216640101000000611cf1565b5061103062ffffff198416600c6020613067565b63ffffffff808416600090815260cd60205260408120549091841610156120925763ffffffff808516600090815260cd6020526040902080549091851690811061207e5761207e613d0b565b9060005260206000200154821490506113cf565b63ffffffff8316158015610a2b5750507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d7571492915050565b6000816120e262ffffff198216640201000000611cf1565b5060006120ee84612c1a565b60ff1614159392505050565b612103816131e1565b50604051339073ffffffffffffffffffffffffffffffffffffffff8316907ff2b3869e9727d6dfa6823415649eb18a3bbb7cf9aa2af02af10aaf8d10e1409590600090a350565b6121548383613244565b5060ff546040517fbb99e8fa00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063bb99e8fa90602401600060405180830381600087803b1580156121c057600080fd5b505af11580156121d4573d6000803e3d6000fd5b505060405133925073ffffffffffffffffffffffffffffffffffffffff84811692508516907f70f97c2b606c3d7af38fff3f924c8396f5a05d266b5dc523d863ad27a1d7518a90600090a4505050565b600082600001828154811061223b5761223b613d0b565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b81548152602001906001019080831161228a575b50505050509050919050565b600061057b606683612e31565b60006113cf8373ffffffffffffffffffffffffffffffffffffffff84166132cb565b600054610100900460ff166123565760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161064b565b61065433611743565b61236761393e565b600081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560208201527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3060408201527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba8560608201527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a1934460808201527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d60a08201527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a196860c08201527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f8360e08201527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af6101008201527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e06101208201527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a56101408201527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8926101608201527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c6101808201527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb6101a08201527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc6101c08201527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d26101e08201527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f6102008201527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a6102208201527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a06102408201527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa06102608201527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e26102808201527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd96102a08201527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3776102c08201527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee6526102e08201527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef6103008201527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d6103208201527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d06103408201527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e6103608201527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e6103808201527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea3226103a08201527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d7356103c08201527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a96103e082015290565b6000805b60208110156128d557600184821c8116908190036128815785826020811061284e5761284e613d0b565b015460408051602081019290925281018490526060016040516020818303038152906040528051906020012092506128cc565b8284836020811061289457612894613d0b565b60200201516040516020016128b3929190918252602082015260400190565b6040516020818303038152906040528051906020012092505b50600101612824565b509392505050565b600061057b826401010000005b8151600090602084016113ba64ffffffffff85168284612ff0565b60008161291d62ffffff198216640301020000611cf1565b5061103062ffffff19841660006002613037565b60008161294962ffffff198216640301020000611cf1565b5061103062ffffff1984166026600c613037565b60008161297562ffffff198216640301020000611cf1565b5061103062ffffff198416601a600c613037565b6000816129a162ffffff198216640301020000611cf1565b5061103062ffffff198416600e600c613037565b6000816129cd62ffffff198216640301020000611cf1565b5061103062ffffff1984166002600c613037565b60655473ffffffffffffffffffffffffffffffffffffffff1633146106545760405162461bcd60e51b815260206004820152600d60248201527f2173797374656d526f7574657200000000000000000000000000000000000000604482015260640161064b565b82518251604051606092612a6792600192889088908890602001613dc7565b60405160208183030381529060405290509392505050565b63ffffffff8116600090815260cd602052604090205415612aa257612aa2613e59565b63ffffffff16600081815260cd602090815260408083208054600181810183559185528385207f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d75791015593835260ce82528220805493840181558252812090910155565b6001612b1460206002613fa8565b612b1e9190613d3a565b821115612b6d5760405162461bcd60e51b815260206004820152601060248201527f6d65726b6c6520747265652066756c6c00000000000000000000000000000000604482015260640161064b565b60005b6020811015612c0c5782600116600103612b9f5781848260208110612b9757612b97613d0b565b015550505050565b838160208110612bb157612bb1613d0b565b01546040805160208101929092528101839052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120600193841c9390925001612b70565b50612c15613e59565b505050565b600061057b62ffffff198316826001613037565b600062ffffff1980841603612c855760405162461bcd60e51b815260206004820152601a60248201527f636f7079546f3a204e756c6c20706f696e746572206465726566000000000000604482015260640161064b565b612c8e8361331a565b612cda5760405162461bcd60e51b815260206004820152601d60248201527f636f7079546f3a20496e76616c696420706f696e746572206465726566000000604482015260640161064b565b6000612cf48460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff1690506000612d0f85612f90565b6bffffffffffffffffffffffff169050600080604051915085821115612d355760206060fd5b8386858560045afa905080612d8c5760405162461bcd60e51b815260206004820152601460248201527f6964656e746974793a206f7574206f6620676173000000000000000000000000604482015260640161064b565b612dbc612d9888612e82565b70ffffffffff000000000000000000000000606091821b168817901b851760181b90565b979650505050505050565b600080612dd383612f90565b6bffffffffffffffffffffffff1690506000612dfd8460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff169091209392505050565b6000806000612e248585613356565b915091506128d58161339b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156113cf565b60008164ffffffffff16612e7384612e82565b64ffffffffff16149392505050565b6000806060612e92816018613d4d565b612e9c9190613d4d565b9290921c92915050565b600080601f5b600f8160ff161115612f19576000612ec5826008613fb4565b60ff1685901c9050612ed681613587565b61ffff16841793508160ff16601014612ef157601084901b93505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612eac565b50600f5b60ff8160ff161015612f8a576000612f36826008613fb4565b60ff1685901c9050612f4781613587565b61ffff16831792508160ff16600014612f6257601083901b92505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612f1d565b50915091565b600080612f9f60606018613d4d565b9290921c6bffffffffffffffffffffffff1692915050565b6000612fd18260181c6bffffffffffffffffffffffff1690565b612fda83612f90565b016bffffffffffffffffffffffff169050919050565b600080612ffd8385613d4d565b905060405181111561300d575060005b806000036130225762ffffff199150506113cf565b5050606092831b9190911790911b1760181b90565b6000613044826020613fd0565b61304f906008613fb4565b60ff1661305d858585613067565b901c949350505050565b60008160ff1660000361307c575060006113cf565b6130948460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff166130af60ff841685613d4d565b1115613118576130ff6130c185612f90565b6bffffffffffffffffffffffff166130e78660181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff16858560ff166135b9565b60405162461bcd60e51b815260040161064b9190613d60565b60208260ff16111561316c5760405162461bcd60e51b815260206004820152601960248201527f496e6465783a206d6f7265207468616e20333220627974657300000000000000604482015260640161064b565b60088202600061317b86612f90565b6bffffffffffffffffffffffff16905060007f80000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84011d91909501511695945050505050565b60006131ee609983613627565b905080156111205760405173ffffffffffffffffffffffffffffffffffffffff831681527f59926e0a78d12238b668b31c8e3f6ece235a59a00ede111d883e255b68c4d0489060200160405180910390a1919050565b6000827f000000000000000000000000000000000000000000000000000000000000000063ffffffff168163ffffffff16146132c25760405162461bcd60e51b815260206004820152600c60248201527f216c6f63616c446f6d61696e0000000000000000000000000000000000000000604482015260640161064b565b610a2b83613649565b60008181526001830160205260408120546133125750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561057b565b50600061057b565b600061332582612e82565b64ffffffffff1664ffffffffff0361333f57506000919050565b600061334a83612fb7565b60405110199392505050565b600080825160410361338c5760208301516040840151606085015160001a613380878285856136d7565b94509450505050613394565b506000905060025b9250929050565b60008160048111156133af576133af613d98565b036133b75750565b60018160048111156133cb576133cb613d98565b036134185760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161064b565b600281600481111561342c5761342c613d98565b036134795760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161064b565b600381600481111561348d5761348d613d98565b036135005760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161064b565b600481600481111561351457613514613d98565b036106ea5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161064b565b600061359960048360ff16901c6137ef565b60ff1661ffff919091161760081b6135b0826137ef565b60ff1617919050565b606060006135c686612ea6565b91505060006135d486612ea6565b91505060006135e286612ea6565b91505060006135f086612ea6565b9150508383838360405160200161360a9493929190613fe9565b604051602081830303815290604052945050505050949350505050565b60006113cf8373ffffffffffffffffffffffffffffffffffffffff841661384b565b6000613654826122aa565b90508015611120577f0000000000000000000000000000000000000000000000000000000000000000613688606684613627565b5060405173ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff8216907f3e006f5b97c04e82df349064761281b0981d45330c2f3e57cc032203b0e31b6b9060200161154b565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561370e57506000905060036137e6565b8460ff16601b1415801561372657508460ff16601c14155b1561373757506000905060046137e6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561378b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166137df576000600192509250506137e6565b9150600090505b94509492505050565b6040805180820190915260108082527f30313233343536373839616263646566000000000000000000000000000000006020830152600091600f8416918290811061383c5761383c613d0b565b016020015160f81c9392505050565b6000818152600183016020526040812054801561393457600061386f600183613d3a565b855490915060009061388390600190613d3a565b90508181146138e85760008660000182815481106138a3576138a3613d0b565b90600052602060002001549050808760000184815481106138c6576138c6613d0b565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806138f9576138f9614126565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061057b565b600091505061057b565b6040518061040001604052806020906020820280368337509192915050565b803563ffffffff8116811461112057600080fd5b60006020828403121561398357600080fd5b6113cf8261395d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126139cc57600080fd5b813567ffffffffffffffff808211156139e7576139e761398c565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613a2d57613a2d61398c565b81604052838152866020858801011115613a4657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215613a7857600080fd5b813567ffffffffffffffff811115613a8f57600080fd5b610a2b848285016139bb565b600060208284031215613aad57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b0257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613ad0565b50909695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106ea57600080fd5b600060208284031215613b4257600080fd5b81356113cf81613b0e565b600080600080600060a08688031215613b6557600080fd5b613b6e8661395d565b945060208601359350613b836040870161395d565b9250606086013567ffffffffffffffff80821115613ba057600080fd5b613bac89838a016139bb565b93506080880135915080821115613bc257600080fd5b50613bcf888289016139bb565b9150509295509295909350565b60008060408385031215613bef57600080fd5b613bf88361395d565b9150613c066020840161395d565b90509250929050565b600060208284031215613c2157600080fd5b81516113cf81613b0e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff818116838216019080821115611fa857611fa8613c2c565b60005b83811015613c93578181015183820152602001613c7b565b50506000910152565b60008151808452613cb4816020860160208601613c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000613cf96040830185613c9c565b82810360208401526113ba8185613c9c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561057b5761057b613c2c565b8082018082111561057b5761057b613c2c565b6020815260006113cf6020830184613c9c565b6bffffffffffffffffffffffff818116838216019080821115611fa857611fa8613c2c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60007fffff000000000000000000000000000000000000000000000000000000000000808960f01b168352808860f01b166002840152808760f01b166004840152508451613e1c816006850160208901613c78565b845190830190613e33816006840160208901613c78565b8451910190613e49816006840160208801613c78565b0160060198975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600181815b80851115613ee157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613ec757613ec7613c2c565b80851615613ed457918102915b93841c9390800290613e8d565b509250929050565b600082613ef85750600161057b565b81613f055750600061057b565b8160018114613f1b5760028114613f2557613f41565b600191505061057b565b60ff841115613f3657613f36613c2c565b50506001821b61057b565b5060208310610133831016604e8410600b8410161715613f64575081810a61057b565b613f6e8383613e88565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613fa057613fa0613c2c565b029392505050565b60006113cf8383613ee9565b60ff8181168382160290811690818114611fa857611fa8613c2c565b60ff828116828216039081111561057b5761057b613c2c565b7f54797065644d656d566965772f696e646578202d204f76657272616e2074686581527f20766965772e20536c696365206973206174203078000000000000000000000060208201527fffffffffffff000000000000000000000000000000000000000000000000000060d086811b821660358401527f2077697468206c656e6774682030780000000000000000000000000000000000603b840181905286821b8316604a8501527f2e20417474656d7074656420746f20696e646578206174206f6666736574203060508501527f7800000000000000000000000000000000000000000000000000000000000000607085015285821b83166071850152607784015283901b1660868201527f2e00000000000000000000000000000000000000000000000000000000000000608c8201526000608d82016105d1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212208be254d5df237d7413af83cc26bd124245b62dce2b17940d869cf78adc7d760c64736f6c63430008110033","runtime-code":"0x6080604052600436106101a15760003560e01c8063a394a0e6116100e1578063f2fde38b1161008a578063f85b597e11610064578063f85b597e146104c1578063f94adcb4146104ee578063fbde22f714610529578063ffa1ad741461054957600080fd5b8063f2fde38b1461046e578063f646a5121461048e578063f7560e40146104ae57600080fd5b8063c4d66de8116100bb578063c4d66de8146103f2578063dd0f1f7414610412578063e65b6bd41461044e57600080fd5b8063a394a0e61461039c578063bf61e67e146103bc578063c07dc7f5146103d257600080fd5b8063715018a61161014e5780638e62e9ef116101285780638e62e9ef146103305780639817e315146103455780639fe03fa214610367578063a340abc11461037c57600080fd5b8063715018a6146102bb5780638d3638f4146102d25780638da5cb5b1461030557600080fd5b8063529d15491161017f578063529d1549146102195780635815869d1461026b578063629ddf691461029b57600080fd5b8063141c4985146101a6578063246c2449146101e0578063522ae00214610203575b600080fd5b3480156101b257600080fd5b506101c66101c1366004613971565b610570565b60405163ffffffff90911681526020015b60405180910390f35b3480156101ec57600080fd5b506101f5610581565b6040519081526020016101d7565b34801561020f57600080fd5b506101f561080081565b34801561022557600080fd5b506065546102469073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d7565b34801561027757600080fd5b5061028b610286366004613a66565b610592565b60405190151581526020016101d7565b3480156102a757600080fd5b506102466102b6366004613a9b565b6105db565b3480156102c757600080fd5b506102d06105e8565b005b3480156102de57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006101c6565b34801561031157600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610246565b34801561033c57600080fd5b506101f5610656565b34801561035157600080fd5b5061035a610662565b6040516101d79190613ab4565b34801561037357600080fd5b5061035a61066e565b34801561038857600080fd5b506102d0610397366004613b30565b61067a565b3480156103a857600080fd5b506102d06103b7366004613b30565b6106ed565b3480156103c857600080fd5b506101c66110ad81565b3480156103de57600080fd5b506102466103ed366004613a9b565b610761565b3480156103fe57600080fd5b506102d061040d366004613b30565b61076e565b34801561041e57600080fd5b5061043261042d366004613971565b6108c1565b6040805163ffffffff90931683526020830191909152016101d7565b34801561045a57600080fd5b506101f5610469366004613971565b6108e9565b34801561047a57600080fd5b506102d0610489366004613b30565b610915565b34801561049a57600080fd5b5061028b6104a9366004613a66565b610a0e565b6104326104bc366004613b4d565b610a33565b3480156104cd57600080fd5b5060ff546102469073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104fa57600080fd5b5061050e610509366004613bdc565b610c6d565b604080519384526020840192909252908201526060016101d7565b34801561053557600080fd5b506102d0610544366004613b30565b610dfb565b34801561055557600080fd5b5061055e600081565b60405160ff90911681526020016101d7565b600061057b82610ea9565b92915050565b600061058d6099610eef565b905090565b60008060006105a084610ef9565b9150915060006105b58262ffffff1916610ff2565b905060006105c282611039565b90506105d1848284868a611125565b9695505050505050565b600061057b6099836113c3565b60335473ffffffffffffffffffffffffffffffffffffffff1633146106545760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b565b600061058d6066610eef565b606061058d60666113d6565b606061058d60996113d6565b60335473ffffffffffffffffffffffffffffffffffffffff1633146106e15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b6106ea816113e3565b50565b60ff5473ffffffffffffffffffffffffffffffffffffffff1633146107545760405162461bcd60e51b815260206004820152600e60248201527f216e6f746172794d616e61676572000000000000000000000000000000000000604482015260640161064b565b61075d816114c0565b5050565b600061057b6066836113c3565b600061077a6001611558565b905080156107af57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6107b76116aa565b6107c0826113e3565b60ff54604080517f9d54c79d000000000000000000000000000000000000000000000000000000008152905161085a9273ffffffffffffffffffffffffffffffffffffffff1691639d54c79d9160048083019260209291908290030181865afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108559190613c0f565b6114c0565b50801561075d57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6000806108cd83610570565b91506000806108dc8585610c6d565b5094969095509350505050565b600061057b6108f783610ea9565b63ffffffff808516600090815260cc60205260409020919061172f16565b60335473ffffffffffffffffffffffffffffffffffffffff16331461097c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b73ffffffffffffffffffffffffffffffffffffffff8116610a055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161064b565b6106ea81611743565b6000806000610a1c846117ba565b91509150610a2b8282866117d8565b949350505050565b600080610a3e610656565b600003610a8d5760405162461bcd60e51b815260206004820152600960248201527f216e6f7461726965730000000000000000000000000000000000000000000000604482015260640161064b565b61080083511115610ae05760405162461bcd60e51b815260206004820152600c60248201527f6d736720746f6f206c6f6e670000000000000000000000000000000000000000604482015260640161064b565b6000610aeb856118a8565b9050610afc62ffffff1982166118b9565b610b485760405162461bcd60e51b815260206004820152601160248201527f21746970733a20666f726d617474696e67000000000000000000000000000000604482015260640161064b565b34610b5862ffffff198316611900565b6bffffffffffffffffffffffff1614610bb35760405162461bcd60e51b815260206004820152601060248201527f21746970733a20746f74616c5469707300000000000000000000000000000000604482015260640161064b565b610bbc88610570565b610bc7906001613c5b565b92506000610c037f0000000000000000000000000000000000000000000000000000000000000000610bf88a611944565b868c8c8c8c8c6119a3565b8051602082012093509050610c19898585611a51565b8863ffffffff168463ffffffff16847fada9f9f4bf16282091ddc28e7d70838404cd5bdff1b87d8650339e8d02b7753d8985604051610c59929190613ce6565b60405180910390a450509550959350505050565b63ffffffff8216600090815260cd60205260408120548190819015610d765763ffffffff808616600090815260cd602052604090205490851610610cf35760405162461bcd60e51b815260206004820152601c60248201527f216e6f6e63653a206578697374696e672064657374696e6174696f6e00000000604482015260640161064b565b63ffffffff808616600090815260cd60205260409020805490918616908110610d1e57610d1e613d0b565b906000526020600020015460ce60008763ffffffff1663ffffffff1681526020019081526020016000208563ffffffff1681548110610d5f57610d5f613d0b565b906000526020600020015443925092509250610df4565b63ffffffff841615610dca5760405162461bcd60e51b815260206004820152601b60248201527f216e6f6e63653a20756e6b6e6f776e2064657374696e6174696f6e0000000000604482015260640161064b565b507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757915060009050435b9250925092565b60335473ffffffffffffffffffffffffffffffffffffffff163314610e625760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064b565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b63ffffffff8116600090815260cd60205260408120548103610ecd57506000919050565b63ffffffff8216600090815260cd602052604090205461057b90600190613d3a565b600061057b825490565b600080610f0583611b11565b9050610f1662ffffff198216611b22565b610f625760405162461bcd60e51b815260206004820152600c60248201527f4e6f742061207265706f72740000000000000000000000000000000000000000604482015260640161064b565b610f96610f7462ffffff198316611b91565b610f91610f8662ffffff198516611bcf565b62ffffff1916611c1a565b611c6d565b9150610fa182611ce4565b610fed5760405162461bcd60e51b815260206004820152601560248201527f5369676e6572206973206e6f7420612067756172640000000000000000000000604482015260640161064b565b915091565b60008161100a62ffffff198216640201000000611cf1565b50611030600161101c602c6041613d4d565b62ffffff1986169190640101000000611df1565b91505b50919050565b600061104a62ffffff198316611e5c565b6110965760405162461bcd60e51b815260206004820152601260248201527f4e6f7420616e206174746573746174696f6e0000000000000000000000000000604482015260640161064b565b6110ba6110a862ffffff198416611e92565b610f91610f8662ffffff198616611ec4565b90506110d46110ce62ffffff198416611ef5565b82611f21565b6111205760405162461bcd60e51b815260206004820152601660248201527f5369676e6572206973206e6f742061206e6f7461727900000000000000000000604482015260640161064b565b919050565b60008061113762ffffff198616611faf565b9050600061114a62ffffff198716611fda565b9050600061115d62ffffff198816612006565b905061116a838383612032565b156111f25761117e62ffffff1987166120ca565b156111e6578873ffffffffffffffffffffffffffffffffffffffff167f36670329f075c374c3847f464e4acdaa51fc70c69c52cb8317787b237088ec63866040516111c99190613d60565b60405180910390a26111da896120fa565b600093505050506113ba565b600193505050506113ba565b61120162ffffff1987166120ca565b156112db578873ffffffffffffffffffffffffffffffffffffffff167fa0248f358d0f7bb4c63d2bd5a3e521bb7aba00ccfde9442154e4950711a912f88660405161124c9190613d60565b60405180910390a273ffffffffffffffffffffffffffffffffffffffff88167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e478942361129b62ffffff198a16611c1a565b6040516112a89190613d60565b60405180910390a26111e67f0000000000000000000000000000000000000000000000000000000000000000898b61214a565b8873ffffffffffffffffffffffffffffffffffffffff167f36670329f075c374c3847f464e4acdaa51fc70c69c52cb8317787b237088ec63866040516113219190613d60565b60405180910390a2611332896120fa565b73ffffffffffffffffffffffffffffffffffffffff88167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e478942361137962ffffff198a16611c1a565b6040516113869190613d60565b60405180910390a26111da7f000000000000000000000000000000000000000000000000000000000000000089600061214a565b95945050505050565b60006113cf8383612224565b9392505050565b606060006113cf8361224e565b73ffffffffffffffffffffffffffffffffffffffff81163b6114475760405162461bcd60e51b815260206004820152601760248201527f21636f6e7472616374206e6f746172794d616e61676572000000000000000000604482015260640161064b565b60ff80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe3befd3a32a53f50ff7d1421555fbd40e5ead3a7ed75417db43a23faffe093169060200160405180910390a150565b60006114cb826122aa565b1590508015611120577f00000000000000000000000000000000000000000000000000000000000000006115006066846122b7565b5060405173ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff8216907f62d8d15324cce2626119bb61d595f59e655486b1ab41b52c0793d814fe03c355906020015b60405180910390a2611033565b60008054610100900460ff16156115f5578160ff16600114801561157b5750303b155b6115ed5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161064b565b506000919050565b60005460ff8084169116106116725760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161064b565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff92909216919091179055600190565b600054610100900460ff166117275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161064b565b6106546122d9565b60006113cf838361173e61235f565b612820565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806117c6836128dd565b90506117d181611039565b9150915091565b6000806117ea62ffffff198516611faf565b905060006117fd62ffffff198616611fda565b9050600061181062ffffff198716612006565b905061181d838383612032565b93508361189e578673ffffffffffffffffffffffffffffffffffffffff167fa458d78fa8902ff24cc896d608e762eb06543f0541124e5582e928e1e47894238660405161186a9190613d60565b60405180910390a261189e7f000000000000000000000000000000000000000000000000000000000000000088600061214a565b5050509392505050565b600061057b826403010200006128ea565b6000601882901c6bffffffffffffffffffffffff1660028110156118e05750600092915050565b60016118eb84612905565b61ffff16148015611030575060321492915050565b600061190b82612931565b6119148361295d565b61191d84612989565b611926856129b5565b6119309190613d73565b61193a9190613d73565b61057b9190613d73565b60007fffffffffffffffffffffffff00000000000000000000000000000000000000008214611974573392915050565b61197c6129e1565b507fffffffffffffffffffffffff0000000000000000000000000000000000000000919050565b604080517e0100000000000000000000000000000000000000000000000000000000000060208201527fffffffff0000000000000000000000000000000000000000000000000000000060e08b811b82166022840152602683018b905289811b8216604684015288811b8216604a840152604e830188905286901b16606e820152815180820360520181526072909101909152606090611a44908484612a48565b9998505050505050505050565b63ffffffff8316600090815260cd60205260408120549003611a7657611a7683612a7f565b63ffffffff838116600090815260cc60205260409020611a9c91808516908490612b0616565b63ffffffff808416600090815260cd6020908152604080832060cc9092529091209091611ace91908581169061172f16565b815460018181018455600093845260208085209092019290925563ffffffff909516825260ce855260408220805491820181558252939020439301929092555050565b600061057b826402010000006128ea565b6000601882901c6bffffffffffffffffffffffff16611b43602c6001613d4d565b611b4e906082613d4d565b8114611b5d5750600092915050565b6001611b6884612c1a565b60ff161115611b7a5750600092915050565b611030611b8684610ff2565b62ffffff1916611e5c565b600081611ba962ffffff198216640201000000611cf1565b506110306000611bbb602c6001613d4d565b62ffffff1986169190640201010000611df1565b600081611be762ffffff198216640201000000611cf1565b506000611bf6602c6041613d4d565b611c01906001613d4d565b9050610a2b62ffffff1985168260416301000000611df1565b6060600080611c378460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff1690506040519150819250611c5c8483602001612c2e565b508181016020016040529052919050565b600080611c7f62ffffff198516612dc7565b9050611cd8816040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050610a2b8184612e15565b600061057b609983612e31565b6000611cfd8383612e60565b611dea576000611d1b611d0f85612e82565b64ffffffffff16612ea6565b9150506000611d308464ffffffffff16612ea6565b6040517f5479706520617373657274696f6e206661696c65642e20476f7420307800000060208201527fffffffffffffffffffff0000000000000000000000000000000000000000000060b086811b8216603d8401527f2e20457870656374656420307800000000000000000000000000000000000000604784015283901b16605482015290925060009150605e0160405160208183030381529060405290508060405162461bcd60e51b815260040161064b9190613d60565b5090919050565b600080611dfd86612f90565b6bffffffffffffffffffffffff169050611e1686612fb7565b84611e218784613d4d565b611e2b9190613d4d565b1115611e3e5762ffffff19915050610a2b565b611e488582613d4d565b90506105d18364ffffffffff168286612ff0565b6000611e6a602c6041613d4d565b6bffffffffffffffffffffffff601884901c166bffffffffffffffffffffffff161492915050565b600081611eaa62ffffff198216640101000000611cf1565b5061103062ffffff1984166000602c640101010000611df1565b600081611edc62ffffff198216640101000000611cf1565b5061103062ffffff198416602c60416301000000611df1565b600081611f0d62ffffff198216640101000000611cf1565b5061103062ffffff19841660006004613037565b6000827f000000000000000000000000000000000000000000000000000000000000000063ffffffff168163ffffffff1614611f9f5760405162461bcd60e51b815260206004820152600c60248201527f216c6f63616c446f6d61696e0000000000000000000000000000000000000000604482015260640161064b565b610a2b836122aa565b5092915050565b600081611fc762ffffff198216640101000000611cf1565b5061103062ffffff198416600480613037565b600081611ff262ffffff198216640101000000611cf1565b5061103062ffffff19841660086004613037565b60008161201e62ffffff198216640101000000611cf1565b5061103062ffffff198416600c6020613067565b63ffffffff808416600090815260cd60205260408120549091841610156120925763ffffffff808516600090815260cd6020526040902080549091851690811061207e5761207e613d0b565b9060005260206000200154821490506113cf565b63ffffffff8316158015610a2b5750507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d7571492915050565b6000816120e262ffffff198216640201000000611cf1565b5060006120ee84612c1a565b60ff1614159392505050565b612103816131e1565b50604051339073ffffffffffffffffffffffffffffffffffffffff8316907ff2b3869e9727d6dfa6823415649eb18a3bbb7cf9aa2af02af10aaf8d10e1409590600090a350565b6121548383613244565b5060ff546040517fbb99e8fa00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063bb99e8fa90602401600060405180830381600087803b1580156121c057600080fd5b505af11580156121d4573d6000803e3d6000fd5b505060405133925073ffffffffffffffffffffffffffffffffffffffff84811692508516907f70f97c2b606c3d7af38fff3f924c8396f5a05d266b5dc523d863ad27a1d7518a90600090a4505050565b600082600001828154811061223b5761223b613d0b565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b81548152602001906001019080831161228a575b50505050509050919050565b600061057b606683612e31565b60006113cf8373ffffffffffffffffffffffffffffffffffffffff84166132cb565b600054610100900460ff166123565760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161064b565b61065433611743565b61236761393e565b600081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560208201527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3060408201527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba8560608201527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a1934460808201527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d60a08201527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a196860c08201527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f8360e08201527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af6101008201527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e06101208201527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a56101408201527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8926101608201527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c6101808201527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb6101a08201527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc6101c08201527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d26101e08201527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f6102008201527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a6102208201527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a06102408201527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa06102608201527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e26102808201527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd96102a08201527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3776102c08201527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee6526102e08201527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef6103008201527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d6103208201527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d06103408201527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e6103608201527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e6103808201527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea3226103a08201527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d7356103c08201527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a96103e082015290565b6000805b60208110156128d557600184821c8116908190036128815785826020811061284e5761284e613d0b565b015460408051602081019290925281018490526060016040516020818303038152906040528051906020012092506128cc565b8284836020811061289457612894613d0b565b60200201516040516020016128b3929190918252602082015260400190565b6040516020818303038152906040528051906020012092505b50600101612824565b509392505050565b600061057b826401010000005b8151600090602084016113ba64ffffffffff85168284612ff0565b60008161291d62ffffff198216640301020000611cf1565b5061103062ffffff19841660006002613037565b60008161294962ffffff198216640301020000611cf1565b5061103062ffffff1984166026600c613037565b60008161297562ffffff198216640301020000611cf1565b5061103062ffffff198416601a600c613037565b6000816129a162ffffff198216640301020000611cf1565b5061103062ffffff198416600e600c613037565b6000816129cd62ffffff198216640301020000611cf1565b5061103062ffffff1984166002600c613037565b60655473ffffffffffffffffffffffffffffffffffffffff1633146106545760405162461bcd60e51b815260206004820152600d60248201527f2173797374656d526f7574657200000000000000000000000000000000000000604482015260640161064b565b82518251604051606092612a6792600192889088908890602001613dc7565b60405160208183030381529060405290509392505050565b63ffffffff8116600090815260cd602052604090205415612aa257612aa2613e59565b63ffffffff16600081815260cd602090815260408083208054600181810183559185528385207f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d75791015593835260ce82528220805493840181558252812090910155565b6001612b1460206002613fa8565b612b1e9190613d3a565b821115612b6d5760405162461bcd60e51b815260206004820152601060248201527f6d65726b6c6520747265652066756c6c00000000000000000000000000000000604482015260640161064b565b60005b6020811015612c0c5782600116600103612b9f5781848260208110612b9757612b97613d0b565b015550505050565b838160208110612bb157612bb1613d0b565b01546040805160208101929092528101839052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120600193841c9390925001612b70565b50612c15613e59565b505050565b600061057b62ffffff198316826001613037565b600062ffffff1980841603612c855760405162461bcd60e51b815260206004820152601a60248201527f636f7079546f3a204e756c6c20706f696e746572206465726566000000000000604482015260640161064b565b612c8e8361331a565b612cda5760405162461bcd60e51b815260206004820152601d60248201527f636f7079546f3a20496e76616c696420706f696e746572206465726566000000604482015260640161064b565b6000612cf48460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff1690506000612d0f85612f90565b6bffffffffffffffffffffffff169050600080604051915085821115612d355760206060fd5b8386858560045afa905080612d8c5760405162461bcd60e51b815260206004820152601460248201527f6964656e746974793a206f7574206f6620676173000000000000000000000000604482015260640161064b565b612dbc612d9888612e82565b70ffffffffff000000000000000000000000606091821b168817901b851760181b90565b979650505050505050565b600080612dd383612f90565b6bffffffffffffffffffffffff1690506000612dfd8460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff169091209392505050565b6000806000612e248585613356565b915091506128d58161339b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156113cf565b60008164ffffffffff16612e7384612e82565b64ffffffffff16149392505050565b6000806060612e92816018613d4d565b612e9c9190613d4d565b9290921c92915050565b600080601f5b600f8160ff161115612f19576000612ec5826008613fb4565b60ff1685901c9050612ed681613587565b61ffff16841793508160ff16601014612ef157601084901b93505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612eac565b50600f5b60ff8160ff161015612f8a576000612f36826008613fb4565b60ff1685901c9050612f4781613587565b61ffff16831792508160ff16600014612f6257601083901b92505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612f1d565b50915091565b600080612f9f60606018613d4d565b9290921c6bffffffffffffffffffffffff1692915050565b6000612fd18260181c6bffffffffffffffffffffffff1690565b612fda83612f90565b016bffffffffffffffffffffffff169050919050565b600080612ffd8385613d4d565b905060405181111561300d575060005b806000036130225762ffffff199150506113cf565b5050606092831b9190911790911b1760181b90565b6000613044826020613fd0565b61304f906008613fb4565b60ff1661305d858585613067565b901c949350505050565b60008160ff1660000361307c575060006113cf565b6130948460181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff166130af60ff841685613d4d565b1115613118576130ff6130c185612f90565b6bffffffffffffffffffffffff166130e78660181c6bffffffffffffffffffffffff1690565b6bffffffffffffffffffffffff16858560ff166135b9565b60405162461bcd60e51b815260040161064b9190613d60565b60208260ff16111561316c5760405162461bcd60e51b815260206004820152601960248201527f496e6465783a206d6f7265207468616e20333220627974657300000000000000604482015260640161064b565b60088202600061317b86612f90565b6bffffffffffffffffffffffff16905060007f80000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84011d91909501511695945050505050565b60006131ee609983613627565b905080156111205760405173ffffffffffffffffffffffffffffffffffffffff831681527f59926e0a78d12238b668b31c8e3f6ece235a59a00ede111d883e255b68c4d0489060200160405180910390a1919050565b6000827f000000000000000000000000000000000000000000000000000000000000000063ffffffff168163ffffffff16146132c25760405162461bcd60e51b815260206004820152600c60248201527f216c6f63616c446f6d61696e0000000000000000000000000000000000000000604482015260640161064b565b610a2b83613649565b60008181526001830160205260408120546133125750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561057b565b50600061057b565b600061332582612e82565b64ffffffffff1664ffffffffff0361333f57506000919050565b600061334a83612fb7565b60405110199392505050565b600080825160410361338c5760208301516040840151606085015160001a613380878285856136d7565b94509450505050613394565b506000905060025b9250929050565b60008160048111156133af576133af613d98565b036133b75750565b60018160048111156133cb576133cb613d98565b036134185760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161064b565b600281600481111561342c5761342c613d98565b036134795760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161064b565b600381600481111561348d5761348d613d98565b036135005760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161064b565b600481600481111561351457613514613d98565b036106ea5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161064b565b600061359960048360ff16901c6137ef565b60ff1661ffff919091161760081b6135b0826137ef565b60ff1617919050565b606060006135c686612ea6565b91505060006135d486612ea6565b91505060006135e286612ea6565b91505060006135f086612ea6565b9150508383838360405160200161360a9493929190613fe9565b604051602081830303815290604052945050505050949350505050565b60006113cf8373ffffffffffffffffffffffffffffffffffffffff841661384b565b6000613654826122aa565b90508015611120577f0000000000000000000000000000000000000000000000000000000000000000613688606684613627565b5060405173ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff8216907f3e006f5b97c04e82df349064761281b0981d45330c2f3e57cc032203b0e31b6b9060200161154b565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561370e57506000905060036137e6565b8460ff16601b1415801561372657508460ff16601c14155b1561373757506000905060046137e6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561378b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166137df576000600192509250506137e6565b9150600090505b94509492505050565b6040805180820190915260108082527f30313233343536373839616263646566000000000000000000000000000000006020830152600091600f8416918290811061383c5761383c613d0b565b016020015160f81c9392505050565b6000818152600183016020526040812054801561393457600061386f600183613d3a565b855490915060009061388390600190613d3a565b90508181146138e85760008660000182815481106138a3576138a3613d0b565b90600052602060002001549050808760000184815481106138c6576138c6613d0b565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806138f9576138f9614126565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061057b565b600091505061057b565b6040518061040001604052806020906020820280368337509192915050565b803563ffffffff8116811461112057600080fd5b60006020828403121561398357600080fd5b6113cf8261395d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126139cc57600080fd5b813567ffffffffffffffff808211156139e7576139e761398c565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613a2d57613a2d61398c565b81604052838152866020858801011115613a4657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215613a7857600080fd5b813567ffffffffffffffff811115613a8f57600080fd5b610a2b848285016139bb565b600060208284031215613aad57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b0257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613ad0565b50909695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106ea57600080fd5b600060208284031215613b4257600080fd5b81356113cf81613b0e565b600080600080600060a08688031215613b6557600080fd5b613b6e8661395d565b945060208601359350613b836040870161395d565b9250606086013567ffffffffffffffff80821115613ba057600080fd5b613bac89838a016139bb565b93506080880135915080821115613bc257600080fd5b50613bcf888289016139bb565b9150509295509295909350565b60008060408385031215613bef57600080fd5b613bf88361395d565b9150613c066020840161395d565b90509250929050565b600060208284031215613c2157600080fd5b81516113cf81613b0e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff818116838216019080821115611fa857611fa8613c2c565b60005b83811015613c93578181015183820152602001613c7b565b50506000910152565b60008151808452613cb4816020860160208601613c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000613cf96040830185613c9c565b82810360208401526113ba8185613c9c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561057b5761057b613c2c565b8082018082111561057b5761057b613c2c565b6020815260006113cf6020830184613c9c565b6bffffffffffffffffffffffff818116838216019080821115611fa857611fa8613c2c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60007fffff000000000000000000000000000000000000000000000000000000000000808960f01b168352808860f01b166002840152808760f01b166004840152508451613e1c816006850160208901613c78565b845190830190613e33816006840160208901613c78565b8451910190613e49816006840160208801613c78565b0160060198975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600181815b80851115613ee157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613ec757613ec7613c2c565b80851615613ed457918102915b93841c9390800290613e8d565b509250929050565b600082613ef85750600161057b565b81613f055750600061057b565b8160018114613f1b5760028114613f2557613f41565b600191505061057b565b60ff841115613f3657613f36613c2c565b50506001821b61057b565b5060208310610133831016604e8410600b8410161715613f64575081810a61057b565b613f6e8383613e88565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613fa057613fa0613c2c565b029392505050565b60006113cf8383613ee9565b60ff8181168382160290811690818114611fa857611fa8613c2c565b60ff828116828216039081111561057b5761057b613c2c565b7f54797065644d656d566965772f696e646578202d204f76657272616e2074686581527f20766965772e20536c696365206973206174203078000000000000000000000060208201527fffffffffffff000000000000000000000000000000000000000000000000000060d086811b821660358401527f2077697468206c656e6774682030780000000000000000000000000000000000603b840181905286821b8316604a8501527f2e20417474656d7074656420746f20696e646578206174206f6666736574203060508501527f7800000000000000000000000000000000000000000000000000000000000000607085015285821b83166071850152607784015283901b1660868201527f2e00000000000000000000000000000000000000000000000000000000000000608c8201526000608d82016105d1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212208be254d5df237d7413af83cc26bd124245b62dce2b17940d869cf78adc7d760c64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"205284:11941:0:-:0;;;208287:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;720:28;;;;205284:11941;;14:280:1;83:6;136:2;124:9;115:7;111:23;107:32;104:52;;;152:1;149;142:12;104:52;184:9;178:16;234:10;227:5;223:22;216:5;213:33;203:61;;260:1;257;250:12;203:61;283:5;14:280;-1:-1:-1;;;14:280:1:o;:::-;205284:11941:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"205284:11941:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126533:143;;;;;;;;;;-1:-1:-1;126533:143:0;;;;;:::i;:::-;;:::i;:::-;;;545:10:1;533:23;;;515:42;;503:2;488:18;126533:143:0;;;;;;;;104481:95;;;;;;;;;;;;;:::i;:::-;;;714:25:1;;;702:2;687:18;104481:95:0;568:177:1;206058:58:0;;;;;;;;;;;;206107:9;206058:58;;190234:33;;;;;;;;;;-1:-1:-1;190234:33:0;;;;;;;;;;;948:42:1;936:55;;;918:74;;906:2;891:18;190234:33:0;750:248:1;110913:850:0;;;;;;;;;;-1:-1:-1;110913:850:0;;;;;:::i;:::-;;:::i;:::-;;;2464:14:1;;2457:22;2439:41;;2427:2;2412:18;110913:850:0;2299:187:1;104299:107:0;;;;;;;;;;-1:-1:-1;104299:107:0;;;;;:::i;:::-;;:::i;194922:57::-;;;;;;;;;;;;;:::i;:::-;;416:92;;;;;;;;;;-1:-1:-1;842:13:0;416:92;104481:95;186905:85;;;;;;;;;;-1:-1:-1;186977:6:0;;;;186905:85;;96345:97;;;;;;;;;;;;;:::i;95943:105::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;104087:101::-;;;;;;;;;;;;;:::i;210713:135::-;;;;;;;;;;-1:-1:-1;210713:135:0;;;;;:::i;:::-;;:::i;209782:516::-;;;;;;;;;;-1:-1:-1;209782:516:0;;;;;:::i;:::-;;:::i;189405:44::-;;;;;;;;;;;;189445:4;189405:44;;96160:108;;;;;;;;;;-1:-1:-1;96160:108:0;;;;;:::i;:::-;;:::i;208891:205::-;;;;;;;;;;-1:-1:-1;208891:205:0;;;;;:::i;:::-;;:::i;124362:413::-;;;;;;;;;;-1:-1:-1;124362:413:0;;;;;:::i;:::-;;:::i;:::-;;;;4479:10:1;4467:23;;;4449:42;;4522:2;4507:18;;4500:34;;;;4422:18;124362:413:0;4277:263:1;126783:142:0;;;;;;;;;;-1:-1:-1;126783:142:0;;;;;:::i;:::-;;:::i;187787:198::-;;;;;;;;;;-1:-1:-1;187787:198:0;;;;;:::i;:::-;;:::i;108199:544::-;;;;;;;;;;-1:-1:-1;108199:544:0;;;;;:::i;:::-;;:::i;211844:1728::-;;;;;;:::i;:::-;;:::i;206793:35::-;;;;;;;;;;-1:-1:-1;206793:35:0;;;;;;;;125471:852;;;;;;;;;;-1:-1:-1;125471:852:0;;;;;:::i;:::-;;:::i;:::-;;;;6200:25:1;;;6256:2;6241:18;;6234:34;;;;6284:18;;;6277:34;6188:2;6173:18;125471:852:0;5998:319:1;194611:118:0;;;;;;;;;;-1:-1:-1;194611:118:0;;;;;:::i;:::-;;:::i;2480:33::-;;;;;;;;;;;;2512:1;2480:33;;;;;6768:4:1;6756:17;;;6738:36;;6726:2;6711:18;2480:33:0;6596:184:1;126533:143:0;126590:18;126641:27;126655:12;126641:13;:27::i;:::-;126620:49;126533:143;-1:-1:-1;;126533:143:0:o;104481:95::-;104528:7;104554:15;:6;:13;:15::i;:::-;104547:22;;104481:95;:::o;110913:850::-;110975:4;111105:14;111121:19;111144:24;111160:7;111144:15;:24::i;:::-;111104:64;;;;111178:24;111205:33;:11;:31;;;;:33::i;:::-;111178:60;;111457:15;111475:34;111492:16;111475;:34::i;:::-;111457:52;;111686:70;111700:6;111708:7;111717:16;111735:11;111748:7;111686:13;:70::i;:::-;111679:77;110913:850;-1:-1:-1;;;;;;110913:850:0:o;104299:107::-;104356:7;104382:17;:6;104392;104382:9;:17::i;194922:57::-;186977:6;;187117:23;186977:6;185905:10;187117:23;187109:68;;;;-1:-1:-1;;;187109:68:0;;6987:2:1;187109:68:0;;;6969:21:1;;;7006:18;;;6999:30;7065:34;7045:18;;;7038:62;7117:18;;187109:68:0;;;;;;;;;194922:57::o;96345:97::-;96392:7;96418:17;:8;:15;:17::i;95943:105::-;95989:16;96024:17;:8;:15;:17::i;104087:101::-;104131:16;104166:15;:6;:13;:15::i;210713:135::-;186977:6;;187117:23;186977:6;185905:10;187117:23;187109:68;;;;-1:-1:-1;;;187109:68:0;;6987:2:1;187109:68:0;;;6969:21:1;;;7006:18;;;6999:30;7065:34;7045:18;;;7038:62;7117:18;;187109:68:0;6785:356:1;187109:68:0;210792:49:::1;210825:14;210792:17;:49::i;:::-;210713:135:::0;:::o;209782:516::-;207641:13;;;;207619:10;:36;207611:63;;;;-1:-1:-1;;;207611:63:0;;7348:2:1;207611:63:0;;;7330:21:1;7387:2;7367:18;;;7360:30;7426:16;7406:18;;;7399:44;7460:18;;207611:63:0;7146:338:1;207611:63:0;210272:19:::1;210283:7;210272:10;:19::i;:::-;;209782:516:::0;:::o;96160:108::-;96216:7;96242:19;:8;96254:6;96242:11;:19::i;208891:205::-;182085:19;182107:25;182130:1;182107:22;:25::i;:::-;182085:47;;182146:14;182142:65;;;182176:13;:20;;;;;;;;182142:65;208973:29:::1;:27;:29::i;:::-;209012:33;209030:14;209012:17;:33::i;:::-;209066:13;::::0;:22:::1;::::0;;;;;;;209055:34:::1;::::0;209066:13:::1;;::::0;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:13;:22:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;209055:10;:34::i;:::-;;182231:14:::0;182227:99;;;182277:5;182261:21;;;;;;182301:14;;-1:-1:-1;6738:36:1;;182301:14:0;;6726:2:1;6711:18;182301:14:0;;;;;;;182075:257;208891:205;:::o;124362:413::-;124458:18;124478;124526:19;124532:12;124526:5;:19::i;:::-;124512:33;;124555:31;124596:25;124690:78;124721:12;124747:11;124690:17;:78::i;:::-;-1:-1:-1;124362:413:0;;124631:137;;-1:-1:-1;124362:413:0;-1:-1:-1;;;;124362:413:0:o;126783:142::-;126839:7;126865:53;126890:27;126904:12;126890:13;:27::i;:::-;126865:19;;;;;;;;:5;:19;;;;;;:53;:24;:53;:::i;187787:198::-;186977:6;;187117:23;186977:6;185905:10;187117:23;187109:68;;;;-1:-1:-1;;;187109:68:0;;6987:2:1;187109:68:0;;;6969:21:1;;;7006:18;;;6999:30;7065:34;7045:18;;;7038:62;7117:18;;187109:68:0;6785:356:1;187109:68:0;187875:22:::1;::::0;::::1;187867:73;;;::::0;-1:-1:-1;;;187867:73:0;;8146:2:1;187867:73:0::1;::::0;::::1;8128:21:1::0;8185:2;8165:18;;;8158:30;8224:34;8204:18;;;8197:62;8295:8;8275:18;;;8268:36;8321:19;;187867:73:0::1;7944:402:1::0;187867:73:0::1;187950:28;187969:8;187950:18;:28::i;108199:544::-:0;108271:4;108407:15;108424:24;108452:30;108469:12;108452:16;:30::i;:::-;108406:76;;;;108677:59;108696:7;108705:16;108723:12;108677:18;:59::i;:::-;108670:66;108199:544;-1:-1:-1;;;;108199:544:0:o;211844:1728::-;212066:19;212087;95137:16;:14;:16::i;:::-;95157:1;95137:21;95129:43;;;;-1:-1:-1;;;95129:43:0;;8553:2:1;95129:43:0;;;8535:21:1;8592:1;8572:18;;;8565:29;8630:11;8610:18;;;8603:39;8659:18;;95129:43:0;8351:332:1;95129:43:0;206107:9:::1;212181:12;:19;:45;;212173:70;;;::::0;-1:-1:-1;;;212173:70:0;;8890:2:1;212173:70:0::1;::::0;::::1;8872:21:1::0;8929:2;8909:18;;;8902:30;8968:14;8948:18;;;8941:42;9000:18;;212173:70:0::1;8688:336:1::0;212173:70:0::1;212253:12;212268:18;:5;:16;:18::i;:::-;212253:33:::0;-1:-1:-1;212358:13:0::1;-1:-1:-1::0;;212358:11:0;::::1;;:13::i;:::-;212350:43;;;::::0;-1:-1:-1;;;212350:43:0;;9231:2:1;212350:43:0::1;::::0;::::1;9213:21:1::0;9270:2;9250:18;;;9243:30;9309:19;9289:18;;;9282:47;9346:18;;212350:43:0::1;9029:341:1::0;212350:43:0::1;212484:9;212464:16;-1:-1:-1::0;;212464:14:0;::::1;;:16::i;:::-;:29;;;212456:58;;;::::0;-1:-1:-1;;;212456:58:0;;9577:2:1;212456:58:0::1;::::0;::::1;9559:21:1::0;9616:2;9596:18;;;9589:30;9655:18;9635;;;9628:46;9691:18;;212456:58:0::1;9375:340:1::0;212456:58:0::1;212710:19;212716:12;212710:5;:19::i;:::-;:23;::::0;212732:1:::1;212710:23;:::i;:::-;212695:38:::0;-1:-1:-1;212791:20:0::1;212814:354;842:13:::0;212896:33:::1;212918:10;212896:21;:33::i;:::-;212951:12;212991;213029:10;213073:18;213112:5;213145:12;212814:21;:354::i;:::-;213192:18:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;212791:377:0;-1:-1:-1;213278:55:0::1;213293:12:::0;213307;213192:18;213278:14:::1;:55::i;:::-;213536:12;213500:65;;213522:12;213500:65;;213509:11;213500:65;213550:5;213557:7;213500:65;;;;;;;:::i;:::-;;;;;;;;212108:1464;;211844:1728:::0;;;;;;;;:::o;125471:852::-;125711:29;;;125592:7;125711:29;;;:15;:29;;;;;:36;125592:7;;;;125711:40;125707:610;;125821:29;;;;;;;;:15;:29;;;;;:36;125812:45;;;;125804:86;;;;-1:-1:-1;;;125804:86:0;;11259:2:1;125804:86:0;;;11241:21:1;11298:2;11278:18;;;11271:30;11337;11317:18;;;11310:58;11385:18;;125804:86:0;11057:352:1;125804:86:0;125929:29;;;;;;;;:15;:29;;;;;:37;;:29;;:37;;;;;;;;;:::i;:::-;;;;;;;;;125984:27;:41;126012:12;125984:41;;;;;;;;;;;;;;;126026:6;125984:49;;;;;;;;;;:::i;:::-;;;;;;;;;126051:12;125904:173;;;;;;;;125707:610;126199:11;;;;126191:51;;;;-1:-1:-1;;;126191:51:0;;11805:2:1;126191:51:0;;;11787:21:1;11844:2;11824:18;;;11817:30;11883:29;11863:18;;;11856:57;11930:18;;126191:51:0;11603:351:1;126191:51:0;-1:-1:-1;126264:15:0;;-1:-1:-1;126289:1:0;;-1:-1:-1;126293:12:0;125707:610;125471:852;;;;;:::o;194611:118::-;186977:6;;187117:23;186977:6;185905:10;187117:23;187109:68;;;;-1:-1:-1;;;187109:68:0;;6987:2:1;187109:68:0;;;6969:21:1;;;7006:18;;;6999:30;7065:34;7045:18;;;7038:62;7117:18;;187109:68:0;6785:356:1;187109:68:0;194694:12:::1;:28:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;194611:118::o;139047:420::-;139275:29;;;139114:7;139275:29;;;:15;:29;;;;;:36;:41;;139271:55;;-1:-1:-1;139325:1:0;;139047:420;-1:-1:-1;139047:420:0:o;139271:55::-;139420:29;;;;;;;:15;:29;;;;;:36;:40;;139459:1;;139420:40;:::i;89731:115::-;89794:7;89820:19;89828:3;85346:18;;85264:107;101767:376;101861:14;101877:13;101914:22;:7;:20;:22::i;:::-;101906:30;-1:-1:-1;101954:16:0;-1:-1:-1;;101954:14:0;;;:16::i;:::-;101946:41;;;;-1:-1:-1;;;101946:41:0;;12294:2:1;101946:41:0;;;12276:21:1;12333:2;12313:18;;;12306:30;12372:14;12352:18;;;12345:42;12404:18;;101946:41:0;12092:336:1;101946:41:0;102006:70;102025:18;-1:-1:-1;;102025:16:0;;;:18::i;:::-;102045:30;:22;-1:-1:-1;;102045:20:0;;;:22::i;:::-;-1:-1:-1;;102045:28:0;;:30::i;:::-;102006:18;:70::i;:::-;101997:79;;102094:16;102103:6;102094:8;:16::i;:::-;102086:50;;;;-1:-1:-1;;;102086:50:0;;12635:2:1;102086:50:0;;;12617:21:1;12674:2;12654:18;;;12647:30;12713:23;12693:18;;;12686:51;12754:18;;102086:50:0;12433:345:1;102086:50:0;101767:376;;;:::o;64024:306::-;64109:7;64093:5;58014:37;-1:-1:-1;;58014:16:0;;40892;58014;:37::i;:::-;-1:-1:-1;64147:176:0::1;57205:1;48749:28;48620:2;48775;48749:28;:::i;:::-;-1:-1:-1::0;;64147:11:0;::::1;::::0;:176;40153:16:::1;64147:11;:176::i;:::-;64128:195;;58061:1;64024:306:::0;;;;:::o;81355:333::-;81419:15;81454:21;-1:-1:-1;;81454:19:0;;;:21::i;:::-;81446:52;;;;-1:-1:-1;;;81446:52:0;;13115:2:1;81446:52:0;;;13097:21:1;13154:2;13134:18;;;13127:30;13193:20;13173:18;;;13166:48;13231:18;;81446:52:0;12913:342:1;81446:52:0;81518:76;81537:23;-1:-1:-1;;81537:21:0;;;:23::i;:::-;81562:31;:23;-1:-1:-1;;81562:21:0;;;:23::i;81518:76::-;81508:86;-1:-1:-1;81612:42:0;81622:22;-1:-1:-1;;81622:20:0;;;:22::i;:::-;81646:7;81612:9;:42::i;:::-;81604:77;;;;-1:-1:-1;;;81604:77:0;;13462:2:1;81604:77:0;;;13444:21:1;13501:2;13481:18;;;13474:30;13540:24;13520:18;;;13513:52;13582:18;;81604:77:0;13260:346:1;81604:77:0;81355:333;;;:::o;132299:1887::-;132497:4;;132542:38;-1:-1:-1;;132542:36:0;;;:38::i;:::-;132513:67;-1:-1:-1;132590:20:0;132613:32;-1:-1:-1;;132613:30:0;;;:32::i;:::-;132590:55;-1:-1:-1;132655:20:0;132678:31;-1:-1:-1;;132678:29:0;;;:31::i;:::-;132655:54;;132723:69;132743:19;132764:13;132779:12;132723:19;:69::i;:::-;132719:1461;;;132846:27;-1:-1:-1;;132846:25:0;;;:27::i;:::-;132842:393;;;133001:6;132985:32;;;133009:7;132985:32;;;;;;:::i;:::-;;;;;;;;133035:19;133047:6;133035:11;:19::i;:::-;133079:5;133072:12;;;;;;;132842:393;133216:4;133209:11;;;;;;;132719:1461;133303:27;-1:-1:-1;;133303:25:0;;;:27::i;:::-;133299:871;;;133460:6;133441:35;;;133468:7;133441:35;;;;;;:::i;:::-;;;;;;;;133499:51;;;;133525:24;-1:-1:-1;;133525:22:0;;;:24::i;:::-;133499:51;;;;;;:::i;:::-;;;;;;;;133568:75;842:13;133617:7;133634:6;133568:12;:75::i;133299:871::-;133819:6;133803:32;;;133827:7;133803:32;;;;;;:::i;:::-;;;;;;;;133853:19;133865:6;133853:11;:19::i;:::-;133895:51;;;;133921:24;-1:-1:-1;;133921:22:0;;;:24::i;:::-;133895:51;;;;;;:::i;:::-;;;;;;;;134046:79;842:13;134095:7;134120:1;134046:12;:79::i;132299:1887::-;;;;;;;;:::o;90188:156::-;90262:7;90312:22;90316:3;90328:5;90312:3;:22::i;:::-;90304:31;90188:156;-1:-1:-1;;;90188:156:0:o;90884:300::-;90947:16;90975:22;91000:19;91008:3;91000:7;:19::i;214229:275::-;198442:19;;;;214306:79;;;;-1:-1:-1;;;214306:79:0;;14035:2:1;214306:79:0;;;14017:21:1;14074:2;14054:18;;;14047:30;14113:25;14093:18;;;14086:53;14156:18;;214306:79:0;13833:347:1;214306:79:0;214395:13;:46;;;;;;;;;;;;;214456:41;;918:74:1;;;214456:41:0;;906:2:1;891:18;214456:41:0;;;;;;;214229:275;:::o;97446:573::-;97501:16;97611:18;97621:7;97611:9;:18::i;:::-;97610:19;97596:33;;97643:11;97639:374;;;842:13;97846:21;:8;97859:7;97846:12;:21::i;:::-;-1:-1:-1;97886:27:0;;948:42:1;936:55;;918:74;;97886:27:0;;;;;;906:2:1;891:18;97886:27:0;;;;;;;;97969:33;209782:516;184261:808;184325:4;184658:13;;;;;;;184654:409;;;184712:7;:12;;184723:1;184712:12;:61;;;;-1:-1:-1;184767:4:0;198442:19;:23;184712:61;184687:166;;;;-1:-1:-1;;;184687:166:0;;14387:2:1;184687:166:0;;;14369:21:1;14426:2;14406:18;;;14399:30;14465:34;14445:18;;;14438:62;14536:16;14516:18;;;14509:44;14570:19;;184687:166:0;14185:410:1;184687:166:0;-1:-1:-1;184874:5:0;;184261:808;-1:-1:-1;184261:808:0:o;184654:409::-;184918:12;;:22;;;;:12;;:22;184910:81;;;;-1:-1:-1;;;184910:81:0;;14387:2:1;184910:81:0;;;14369:21:1;14426:2;14406:18;;;14399:30;14465:34;14445:18;;;14438:62;14536:16;14516:18;;;14509:44;14570:19;;184910:81:0;14185:410:1;184910:81:0;-1:-1:-1;185005:12:0;:22;;;;;;;;;;;;;;;-1:-1:-1;;184261:808:0:o;193915:108::-;183672:13;;;;;;;183664:69;;;;-1:-1:-1;;;183664:69:0;;14802:2:1;183664:69:0;;;14784:21:1;14841:2;14821:18;;;14814:30;14880:34;14860:18;;;14853:62;14951:13;14931:18;;;14924:41;14982:19;;183664:69:0;14600:407:1;183664:69:0;193990:26:::1;:24;:26::i;115659:146::-:0;115732:7;115758:40;115770:5;115777:6;115785:12;:10;:12::i;:::-;115758:11;:40::i;188139:187::-;188231:6;;;;188247:17;;;;;;;;;;;188279:40;;188231:6;;;188247:17;188231:6;;188279:40;;188212:16;;188279:40;188202:124;188139:187;:::o;80717:236::-;80817:15;80834:13;80871:32;:12;:30;:32::i;:::-;80863:40;;80923:23;80940:5;80923:16;:23::i;:::-;80913:33;;80717:236;;;:::o;128865:1116::-;129020:12;;129073:38;-1:-1:-1;;129073:36:0;;;:38::i;:::-;129044:67;-1:-1:-1;129121:20:0;129144:32;-1:-1:-1;;129144:30:0;;;:32::i;:::-;129121:55;-1:-1:-1;129186:20:0;129209:31;-1:-1:-1;;129209:29:0;;;:31::i;:::-;129186:54;;129260:69;129280:19;129301:13;129316:12;129260:19;:69::i;:::-;129250:79;;129344:7;129339:636;;129389:7;129372:39;;;129398:12;129372:39;;;;;;:::i;:::-;;;;;;;;129520:79;842:13;129569:7;129594:1;129520:12;:79::i;:::-;129034:947;;;128865:1116;;;;;:::o;148871:138::-;148937:7;148963:39;:8;41829:16;148963:12;:39::i;149957:329::-;150011:4;5611:2;21047:23;;;6004:16;21043:41;150128:1;150119:10;;150115:28;;;-1:-1:-1;150138:5:0;;149957:329;-1:-1:-1;;149957:329:0:o;150115:28::-;146838:1;150220:18;150232:5;150220:11;:18::i;:::-;:34;;;:59;;;;-1:-1:-1;147580:2:0;150258:21;;150213:66;-1:-1:-1;;149957:329:0:o;151872:337::-;151929:6;152184:18;152196:5;152184:11;:18::i;:::-;152165:16;152175:5;152165:9;:16::i;:::-;152141:21;152156:5;152141:14;:21::i;:::-;152122:16;152132:5;152122:9;:16::i;:::-;:40;;;;:::i;:::-;:59;;;;:::i;:::-;:80;;;;:::i;216470:753::-;216544:14;161103:24;216574:38;;216570:647;;216664:10;216628:47;81355:333;-1:-1:-1;;81355:333:0:o;216570:647::-;217061:21;:19;:21::i;:::-;-1:-1:-1;161103:24:0;216470:753;;;:::o;156336:656::-;143816:230;;;17784:16:1;143816:230:0;;;17768:102:1;17889:66;17992:3;17988:16;;;17984:25;;17971:11;;;17964:46;18026:11;;;18019:27;;;18080:16;;;18076:25;;18062:12;;;18055:47;18136:16;;;18132:25;;18118:12;;;18111:47;18174:12;;;18167:28;;;18229:16;;;18225:25;18211:12;;;18204:47;143816:230:0;;;;;;;;;18267:12:1;;;;143816:230:0;;;156615:12;;156658:327;;156936:5;156959:12;156658:13;:327::i;:::-;156639:346;156336:656;-1:-1:-1;;;;;;;;;156336:656:0:o;135373:890::-;135658:29;;;;;;;:15;:29;;;;;:36;:41;;135654:87;;135701:40;135728:12;135701:26;:40::i;:::-;135902:55;:19;;;;;;;:5;:19;;;;;:55;;;;;;135944:12;;135902:26;:55;:::i;:::-;136111:29;;;;;;;;:15;:29;;;;;;;;136146:5;:19;;;;;;136111:29;;136146:39;;:19;:39;;;;:24;:39;:::i;:::-;136111:75;;;;;;;;-1:-1:-1;136111:75:0;;;;;;;;;;;;;;136196:41;;;;;;:27;:41;;;;;:60;;;;;;;;;;;;136243:12;136196:60;;;;;;-1:-1:-1;;135373:890:0:o;60753:134::-;60821:7;60847:33;:8;40892:16;60847:12;:33::i;62656:443::-;62712:4;5611:2;21047:23;;;6004:16;21043:41;57320:27;57265:2;57320:1;:27;:::i;:::-;57395;;57416:6;57395:27;:::i;:::-;62817:6;:23;62813:41;;-1:-1:-1;62849:5:0;;62656:443;-1:-1:-1;;62656:443:0:o;62813:41::-;62951:14;62922:20;62936:5;62922:13;:20::i;:::-;:44;;;62918:62;;;-1:-1:-1;62975:5:0;;62656:443;-1:-1:-1;;62656:443:0:o;62918:62::-;63050:42;:26;63070:5;63050:19;:26::i;:::-;-1:-1:-1;;63050:40:0;;:42::i;64431:317::-;64507:7;64491:5;58014:37;-1:-1:-1;;58014:16:0;;40892;58014;:37::i;:::-;-1:-1:-1;64584:157:0::1;57151:1;57320:27;57265:2;57320:1;:27;:::i;:::-;-1:-1:-1::0;;64584:11:0;::::1;::::0;:157;40991:16:::1;64584:11;:157::i;64826:380::-:0;64906:7;64890:5;58014:37;-1:-1:-1;;58014:16:0;;40892;58014;:37::i;:::-;-1:-1:-1;64925:23:0::1;48749:28;48620:2;48775;48749:28;:::i;:::-;64951:51;::::0;57205:1:::1;64951:51;:::i;:::-;64925:77:::0;-1:-1:-1;65031:168:0::1;-1:-1:-1::0;;65031:11:0;::::1;64925:77:::0;42700:2:::1;39414:16;65031:11;:168::i;34066:632::-:0;34121:16;34149:11;34170:12;34185;34189:7;5611:2;21047:23;6004:16;21043:41;;20527:573;34185:12;34170:27;;;;34307:4;34301:11;34294:18;;34362:3;34355:10;;34408:33;34421:7;34430:3;34436:4;34430:10;34408:12;:33::i;:::-;-1:-1:-1;34565:14:0;;;34581:4;34561:25;34555:4;34548:39;34628:17;;34066:632;;-1:-1:-1;34066:632:0:o;77093:285::-;77203:14;;77250;-1:-1:-1;;77250:12:0;;;:14::i;:::-;77233:31;;77283:36;77312:6;75686:58;;22658:66:1;75686:58:0;;;22646:79:1;22741:12;;;22734:28;;;75556:7:0;;22778:12:1;;75686:58:0;;;;;;;;;;;;75676:69;;;;;;75669:76;;75487:265;;;;77283:36;77274:45;;77338:33;77352:6;77360:10;77338:13;:33::i;105816:123::-;105884:4;105907:25;:6;105923:8;105907:15;:25::i;12629:578::-;12707:7;12731:26;12738:7;12747:9;12731:6;:26::i;:::-;12726:451;;12776:9;12789:35;12807:15;12814:7;12807:6;:15::i;:::-;12799:24;;12789:9;:35::i;:::-;12773:51;;;12841:9;12854:29;12872:9;12864:18;;12854:9;:29::i;:::-;12941:186;;15761:31:1;12941:186:0;;;15749:44:1;15812:66;15916:3;15912:16;;;15908:25;;15894:12;;;15887:47;15964:15;15950:12;;;15943:37;16014:16;;;16010:25;15996:12;;;15989:47;12838:45:0;;-1:-1:-1;12897:17:0;;-1:-1:-1;16052:12:1;;12941:186:0;;;;;;;;;;;;12897:244;;13162:3;13155:11;;-1:-1:-1;;;13155:11:0;;;;;;;;:::i;12726:451::-;-1:-1:-1;13193:7:0;;12629:578;-1:-1:-1;12629:578:0:o;21701:399::-;21840:7;21859:12;21874;21878:7;21874:3;:12::i;:::-;21859:27;;;;21970:12;21974:7;21970:3;:12::i;:::-;21963:4;21947:13;21954:6;21947:4;:13;:::i;:::-;:20;;;;:::i;:::-;:35;21943:77;;;-1:-1:-1;;21998:11:0;;;;;21943:77;22037:13;22044:6;22037:4;:13;:::i;:::-;22030:20;;22067:26;22073:7;22067:26;;22082:4;22088;22067:5;:26::i;51370:124::-;51431:4;48749:28;48620:2;48775;48749:28;:::i;:::-;6004:16;5611:2;21047:23;;;21043:41;51454:33;;;;51370:124;-1:-1:-1;;51370:124:0:o;54781:300::-;54867:7;54851:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;54905:169:0::1;-1:-1:-1::0;;54905:11:0;::::1;48411:1;48620:2;40252:16;54905:11;:169::i;55164:300::-:0;55250:7;55234:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;55288:169:0::1;-1:-1:-1::0;;55288:11:0;::::1;48620:2;42700;39414:16;55288:11;:169::i;53026:178::-:0;53111:6;53095:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;53143:53:0::1;-1:-1:-1::0;;53143:15:0;::::1;48411:1;53192;53143:15;:53::i;99255:203::-:0;99405:4;99379:7;842:13;350:25;;:7;:25;;;342:50;;;;-1:-1:-1;;;342:50:0;;16501:2:1;342:50:0;;;16483:21:1;16540:2;16520:18;;;16513:30;16579:14;16559:18;;;16552:42;16611:18;;342:50:0;16299:336:1;342:50:0;99432:19:::1;99442:8;99432:9;:19::i;402:1::-;99255:203:::0;;;;;:::o;53308:224::-;53430:6;53406:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;53466:58:0::1;-1:-1:-1::0;;53466:15:0;::::1;48465:1;::::0;53466:15:::1;:58::i;53648:176::-:0;53732:6;53716:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;53764:52:0::1;-1:-1:-1::0;;53764:15:0;::::1;48513:1;53812;53764:15;:52::i;54511:164::-:0;54594:7;54578:5;49374:42;-1:-1:-1;;49374:16:0;;40153;49374;:42::i;:::-;-1:-1:-1;54620:48:0::1;-1:-1:-1::0;;54620:11:0;::::1;48560:2;54663;54620:11;:48::i;138082:587::-:0;138244:29;;;;138215:4;138244:29;;;:15;:29;;;;;:36;138215:4;;138235:45;;;138231:242;;;138425:29;;;;;;;;:15;:29;;;;;:37;;:29;;:37;;;;;;;;;:::i;:::-;;;;;;;;;138416:5;:46;138409:53;;;;138231:242;138623:11;;;;:39;;;;-1:-1:-1;;138647:15:0;138638:24;;138616:46;-1:-1:-1;;138082:587:0:o;63752:150::-;63831:4;63815:5;58014:37;-1:-1:-1;;58014:16:0;;40892;58014;:37::i;:::-;-1:-1:-1;63884:10:0::1;63854:20;63868:5:::0;63854:13:::1;:20::i;:::-;:41;;;;::::0;63752:150;-1:-1:-1;;;63752:150:0:o;215342:197::-;215465:20;215478:6;215465:12;:20::i;:::-;-1:-1:-1;215500:32:0;;215521:10;;215500:32;;;;;;;;;215342:197;:::o;214756:421::-;214945:31;214959:7;214968;214945:13;:31::i;:::-;-1:-1:-1;214986:13:0;;:46;;;;;215020:10;214986:46;;;918:74:1;214986:13:0;;;;;:25;;891:18:1;;214986:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;215128:42:0;;215159:10;;-1:-1:-1;215128:42:0;;;;;-1:-1:-1;215128:42:0;;;;;;;;214756:421;;;:::o;85713:118::-;85780:7;85806:3;:11;;85818:5;85806:18;;;;;;;;:::i;:::-;;;;;;;;;85799:25;;85713:118;;;;:::o;86371:109::-;86427:16;86462:3;:11;;86455:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86371:109;;;:::o;99561:117::-;99621:4;99644:27;:8;99662;99644:17;:27::i;88930:150::-;89000:4;89023:50;89028:3;89048:23;;;89023:4;:50::i;186718:111::-;183672:13;;;;;;;183664:69;;;;-1:-1:-1;;;183664:69:0;;14802:2:1;183664:69:0;;;14784:21:1;14841:2;14821:18;;;14814:30;14880:34;14860:18;;;14853:62;14951:13;14931:18;;;14924:41;14982:19;;183664:69:0;14600:407:1;183664:69:0;186790:32:::1;185905:10:::0;186790:18:::1;:32::i;115923:964::-:0;115968:34;;:::i;:::-;116027:3;116014:16;;116053:3;116014:10;116040;;:16;116079:3;116066:10;;;:16;116105:3;116092:10;;;:16;116131:3;116118:10;;;:16;116157:3;116144:10;;;:16;116183:3;116170:10;;;:16;116209:3;116196:10;;;:16;116235:3;116222:10;;;:16;116261:3;116248:10;;;:16;116288:4;116274:11;;;:18;116316:4;116302:11;;;:18;116344:4;116330:11;;;:18;116372:4;116358:11;;;:18;116400:4;116386:11;;;:18;116428:4;116414:11;;;:18;116456:4;116442:11;;;:18;116484:4;116470:11;;;:18;116512:4;116498:11;;;:18;116540:4;116526:11;;;:18;116568:4;116554:11;;;:18;116596:4;116582:11;;;:18;116624:4;116610:11;;;:18;116652:4;116638:11;;;:18;116680:4;116666:11;;;:18;116708:4;116694:11;;;:18;116736:4;116722:11;;;:18;116764:4;116750:11;;;:18;116792:4;116778:11;;;:18;116820:4;116806:11;;;:18;116848:4;116834:11;;;:18;116876:4;116862:11;;;:18;116014:7;115923:964::o;114896:568::-;115042:16;;115070:388;113196:2;115090:1;:14;115070:388;;;115156:4;115141:11;;;115140:20;;;115178:12;;;115174:215;;115248:5;115261:1;115248:15;;;;;;;:::i;:::-;;;115231:43;;;;;;17044:19:1;;;;17079:12;;17072:28;;;17116:12;;115231:43:0;;;;;;;;;;;;115221:54;;;;;;115210:65;;115174:215;;;115352:8;115362:7;115370:1;115362:10;;;;;;;:::i;:::-;;;;;115335:38;;;;;;;;17044:19:1;;;17088:2;17079:12;;17072:28;17125:2;17116:12;;16887:247;115335:38:0;;;;;;;;;;;;;115325:49;;;;;;115314:60;;115174:215;-1:-1:-1;115430:3:0;;115070:388;;;;114896:568;;;;;:::o;50080:144::-;50153:7;50179:38;:8;40153:16;17136:595;17240:10;;17206:7;;17666:4;17657:14;;17698:26;;;;17657:14;17240:10;17698:5;:26::i;150882:149::-;150957:6;150941:5;148172:43;-1:-1:-1;;148172:16:0;;41829;148172;:43::i;:::-;-1:-1:-1;150989:34:0::1;-1:-1:-1::0;;150989:15:0;::::1;147326:1;151021;150989:15;:34::i;151673:151::-:0;151748:6;151732:5;148172:43;-1:-1:-1;;148172:16:0;;41829;148172;:43::i;:::-;-1:-1:-1;151780:36:0::1;-1:-1:-1::0;;151780:15:0;::::1;147531:2;151813;151780:15;:36::i;151478:147::-:0;151551:6;151535:5;148172:43;-1:-1:-1;;148172:16:0;;41829;148172;:43::i;:::-;-1:-1:-1;151583:34:0::1;-1:-1:-1::0;;151583:15:0;::::1;147479:2;151614;151583:15;:34::i;151275:157::-:0;151353:6;151337:5;148172:43;-1:-1:-1;;148172:16:0;;41829;148172;:43::i;:::-;-1:-1:-1;151385:39:0::1;-1:-1:-1::0;;151385:15:0;::::1;147429:2;151421;151385:15;:39::i;151077:147::-:0;151150:6;151134:5;148172:43;-1:-1:-1;;148172:16:0;;41829;148172;:43::i;:::-;-1:-1:-1;151182:34:0::1;-1:-1:-1::0;;151182:15:0;::::1;147375:1;151213:2;151182:15;:34::i;195564:123::-:0;195649:12;;;;195627:10;:35;195619:61;;;;-1:-1:-1;;;195619:61:0;;17341:2:1;195619:61:0;;;17323:21:1;17380:2;17360:18;;;17353:30;17419:15;17399:18;;;17392:43;17452:18;;195619:61:0;17139:337:1;155212:480:0;155540:14;;155580:12;;155466:219;;155357:12;;155466:219;;152714:1;;155540:7;;155580:5;;155659:12;;155466:219;;;:::i;:::-;;;;;;;;;;;;;155447:238;;155212:480;;;;;:::o;134581:457::-;134738:29;;;;;;;:15;:29;;;;;:36;:41;134731:49;;;;:::i;:::-;134921:29;;;;;;:15;:29;;;;;;;;:51;;;;;;;;;;;;;;134956:15;134921:51;;;134982:41;;;:27;:41;;;;:49;;;;;;;;;;;;;;;134581:457::o;113796:817::-;113259:1;113243:13;113196:2;113243:1;:13;:::i;:::-;:17;;;;:::i;:::-;113923:9;:23;;113915:52;;;;-1:-1:-1;;;113915:52:0;;21211:2:1;113915:52:0;;;21193:21:1;21250:2;21230:18;;;21223:30;21289:18;21269;;;21262:46;21325:18;;113915:52:0;21009:340:1;113915:52:0;114099:9;114094:329;113196:2;114114:1;:14;114094:329;;;114151:9;114163:1;114151:13;114169:1;114150:20;114146:106;;114208:5;114190;114203:1;114190:15;;;;;;;:::i;:::-;;:23;-1:-1:-1;;;;113796:817:0:o;114146:106::-;114300:5;114313:1;114300:15;;;;;;;:::i;:::-;;;114283:40;;;;;;17044:19:1;;;;17079:12;;17072:28;;;17116:12;;114283:40:0;;;;;;;;;;;;;114273:51;;114283:40;114273:51;;;;114352:1;114338:15;;;;114273:51;;-1:-1:-1;114395:3:0;114094:329;;;-1:-1:-1;114593:13:0;;:::i;:::-;113796:817;;;:::o;65875:170::-;65935:18;65986:51;-1:-1:-1;;65986:15:0;;65935:18;66033:1;65986:15;:51::i;32803:892::-;32881:15;-1:-1:-1;;10396:15:0;;;;32908:55;;;;-1:-1:-1;;;32908:55:0;;21556:2:1;32908:55:0;;;21538:21:1;21595:2;21575:18;;;21568:30;21634:28;21614:18;;;21607:56;21680:18;;32908:55:0;21354:350:1;32908:55:0;32981:16;32989:7;32981;:16::i;:::-;32973:58;;;;-1:-1:-1;;;32973:58:0;;21911:2:1;32973:58:0;;;21893:21:1;21950:2;21930:18;;;21923:30;21989:31;21969:18;;;21962:59;22038:18;;32973:58:0;21709:353:1;32973:58:0;33041:12;33056;33060:7;5611:2;21047:23;6004:16;21043:41;;20527:573;33056:12;33041:27;;;;33078:15;33096:12;33100:7;33096:3;:12::i;:::-;33078:30;;;;33119:11;33140:8;33258:4;33252:11;33245:18;;33345:7;33340:3;33337:16;33334:94;;;33385:4;33379;33372:18;33334:94;33555:4;33546:7;33540:4;33531:7;33525:4;33518:5;33507:53;33500:60;;33587:3;33579:36;;;;-1:-1:-1;;;33579:36:0;;22269:2:1;33579:36:0;;;22251:21:1;22308:2;22288:18;;;22281:30;22347:22;22327:18;;;22320:50;22387:18;;33579:36:0;22067:344:1;33579:36:0;33636:52;33657:15;33664:7;33657:6;:15::i;:::-;15290:33;5523:2;15290:33;;;;15428:17;;15414:32;;15551:17;;5611:2;15535:34;;14649:936;33636:52;33626:62;32803:892;-1:-1:-1;;;;;;;32803:892:0:o;27884:290::-;27940:14;27966:12;27981;27985:7;27981:3;:12::i;:::-;27966:27;;;;28003:12;28018;28022:7;5611:2;21047:23;6004:16;21043:41;;20527:573;28018:12;28003:27;;28137:21;;;;27884:290;-1:-1:-1;;;27884:290:0:o;71783:227::-;71861:7;71881:17;71900:18;71922:27;71933:4;71939:9;71922:10;:27::i;:::-;71880:69;;;;71959:18;71971:5;71959:11;:18::i;89485:165::-;89618:23;;;89565:4;85152:19;;;:12;;;:19;;;;;;:24;;89588:55;85056:127;12199:132;12273:4;12315:9;12296:28;;:15;12303:7;12296:6;:15::i;:::-;:28;;;;12199:132;-1:-1:-1;;;12199:132:0:o;17923:504::-;17979:12;;5523:2;5795:20;5523:2;5611;5795:20;:::i;:::-;5875;;;;:::i;:::-;18387:24;;;;;17923:504;-1:-1:-1;;17923:504:0:o;7214:667::-;7268:13;;7324:2;7309:258;7332:2;7328:1;:6;;;7309:258;;;7352:11;7379:5;:1;7383;7379:5;:::i;:::-;7372:13;;:2;:13;;7352:34;;7409:14;7417:5;7409:7;:14::i;:::-;7400:23;;;;;;7441:1;:7;;7446:2;7441:7;7437:58;;7478:2;7468:12;;;;;7437:58;-1:-1:-1;7536:6:0;;7309:258;;;-1:-1:-1;7630:2:0;7615:260;7638:3;7634:1;:7;;;7615:260;;;7659:11;7686:5;:1;7690;7686:5;:::i;:::-;7679:13;;:2;:13;;7659:34;;7717:14;7725:5;7717:7;:14::i;:::-;7707:24;;;;;;7749:1;:6;;7754:1;7749:6;7745:58;;7786:2;7775:13;;;;;7745:58;-1:-1:-1;7844:6:0;;7615:260;;;;7214:667;;;:::o;19090:573::-;19143:11;;5795:20;5566:2;5611;5795:20;:::i;:::-;19610:23;;;;6004:16;19606:41;;19090:573;-1:-1:-1;;19090:573:0:o;21274:147::-;21327:7;21392:12;21396:7;5611:2;21047:23;6004:16;21043:41;;20527:573;21392:12;21377;21381:7;21377:3;:12::i;:::-;:27;21370:34;;;;21274:147;;;:::o;16124:615::-;16235:15;;16277:11;16284:4;16277;:11;:::i;:::-;16262:26;;16556:4;16550:11;16544:4;16541:21;16538:66;;;-1:-1:-1;16589:1:0;16538:66;16627:4;16635:1;16627:9;16623:51;;-1:-1:-1;;16652:11:0;;;;;16623:51;-1:-1:-1;;5523:2:0;15290:33;;;15428:17;;;;15414:32;;;15551:17;5611:2;15535:34;;16124:615::o;26330:374::-;26449:14;26680:11;26685:6;26680:2;:11;:::i;:::-;26679:17;;26695:1;26679:17;:::i;:::-;26635:62;;26643:30;26649:7;26658:6;26666;26643:5;:30::i;:::-;26635:62;;;26330:374;-1:-1:-1;;;;26330:374:0:o;25094:890::-;25209:14;25239:6;:11;;25249:1;25239:11;25235:59;;-1:-1:-1;25281:1:0;25266:17;;25235:59;25325:12;25329:7;5611:2;21047:23;6004:16;21043:41;;20527:573;25325:12;25307:30;;:15;;;;:6;:15;:::i;:::-;:30;25303:137;;;25360:68;25376:12;25380:7;25376:3;:12::i;:::-;25360:68;;25390:12;25394:7;5611:2;21047:23;6004:16;21043:41;;20527:573;25390:12;25360:68;;25404:6;25420;25412:15;;25360;:68::i;:::-;25353:76;;-1:-1:-1;;;25353:76:0;;;;;;;;:::i;25303:137::-;25467:2;25457:6;:12;;;;25449:50;;;;-1:-1:-1;;;25449:50:0;;23389:2:1;25449:50:0;;;23371:21:1;23428:2;23408:18;;;23401:30;23467:27;23447:18;;;23440:55;23512:18;;25449:50:0;23187:349:1;25449:50:0;25580:1;25571:10;;25510:15;25616:12;25620:7;25616:3;:12::i;:::-;25601:27;;;-1:-1:-1;25694:13:0;9870:66;9840:12;;;9819:131;25942:17;;;;25936:24;25932:36;;;-1:-1:-1;;;;;25094:890:0:o;105523:214::-;105588:17;105632:21;:6;105646;105632:13;:21::i;:::-;105617:36;;105667:12;105663:68;;;105700:20;;948:42:1;936:55;;918:74;;105700:20:0;;906:2:1;891:18;105700:20:0;;;;;;;105523:214;;;:::o;98189:196::-;98329:4;98303:7;842:13;350:25;;:7;:25;;;342:50;;;;-1:-1:-1;;;342:50:0;;16501:2:1;342:50:0;;;16483:21:1;16540:2;16520:18;;;16513:30;16579:14;16559:18;;;16552:42;16611:18;;342:50:0;16299:336:1;342:50:0;98356:22:::1;98370:7;98356:13;:22::i;83015:404::-:0;83078:4;85152:19;;;:12;;;:19;;;;;;83094:319;;-1:-1:-1;83136:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;83316:18;;83294:19;;;:12;;;:19;;;;;;:40;;;;83348:11;;83094:319;-1:-1:-1;83397:5:0;83390:12;;11069:465;11126:8;11150:15;11157:7;11150:6;:15::i;:::-;:31;;11169:12;11150:31;11146:74;;-1:-1:-1;11204:5:0;;11069:465;-1:-1:-1;11069:465:0:o;11146:74::-;11229:12;11244;11248:7;11244:3;:12::i;:::-;11511:4;11505:11;-1:-1:-1;11492:26:0;;11069:465;-1:-1:-1;;;11069:465:0:o;70267:730::-;70348:7;70357:12;70385:9;:16;70405:2;70385:22;70381:610;;70721:4;70706:20;;70700:27;70770:4;70755:20;;70749:27;70827:4;70812:20;;70806:27;70423:9;70798:36;70868:25;70879:4;70798:36;70700:27;70749;70868:10;:25::i;:::-;70861:32;;;;;;;;;70381:610;-1:-1:-1;70940:1:0;;-1:-1:-1;70944:35:0;70381:610;70267:730;;;;;:::o;68572:631::-;68649:20;68640:5;:29;;;;;;;;:::i;:::-;;68636:561;;68572:631;:::o;68636:561::-;68745:29;68736:5;:38;;;;;;;;:::i;:::-;;68732:465;;68790:34;;-1:-1:-1;;;68790:34:0;;23743:2:1;68790:34:0;;;23725:21:1;23782:2;23762:18;;;23755:30;23821:26;23801:18;;;23794:54;23865:18;;68790:34:0;23541:348:1;68732:465:0;68854:35;68845:5;:44;;;;;;;;:::i;:::-;;68841:356;;68905:41;;-1:-1:-1;;;68905:41:0;;24096:2:1;68905:41:0;;;24078:21:1;24135:2;24115:18;;;24108:30;24174:33;24154:18;;;24147:61;24225:18;;68905:41:0;23894:355:1;68841:356:0;68976:30;68967:5;:39;;;;;;;;:::i;:::-;;68963:234;;69022:44;;-1:-1:-1;;;69022:44:0;;24456:2:1;69022:44:0;;;24438:21:1;24495:2;24475:18;;;24468:30;24534:34;24514:18;;;24507:62;24605:4;24585:18;;;24578:32;24627:19;;69022:44:0;24254:398:1;68963:234:0;69096:30;69087:5;:39;;;;;;;;:::i;:::-;;69083:114;;69142:44;;-1:-1:-1;;;69142:44:0;;24859:2:1;69142:44:0;;;24841:21:1;24898:2;24878:18;;;24871:30;24937:34;24917:18;;;24910:62;25008:4;24988:18;;;24981:32;25030:19;;69142:44:0;24657:398:1;6691:199:0;6741:14;6778:18;6794:1;6788:2;:7;;;;6778:9;:18::i;:::-;6767:29;;6820:13;;;;;;6832:1;6820:13;6854;6864:2;6854:9;:13::i;:::-;6843:24;;;;6691:199;-1:-1:-1;6691:199:0:o;23851:741::-;23997:17;24029:9;24042:15;24052:4;24042:9;:15::i;:::-;24026:31;;;24070:9;24083:15;24093:4;24083:9;:15::i;:::-;24067:31;;;24111:9;24124:17;24134:6;24124:9;:17::i;:::-;24108:33;;;24154:9;24167:17;24177:6;24167:9;:17::i;:::-;24151:33;;;24334:1;24396;24476;24538;24220:355;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;24194:391;;24016:576;;;;23851:741;;;;;;:::o;89248:156::-;89321:4;89344:53;89352:3;89372:23;;;89344:7;:53::i;98491:597::-;98549:18;98660;98670:7;98660:9;:18::i;:::-;98644:34;;98692:13;98688:394;;;842:13;98906:24;:8;98922:7;98906:15;:24::i;:::-;-1:-1:-1;98949:29:0;;948:42:1;936:55;;918:74;;98949:29:0;;;;;;906:2:1;891:18;98949:29:0;750:248:1;73191:1603:0;73317:7;;74241:66;74228:79;;74224:161;;;-1:-1:-1;74339:1:0;;-1:-1:-1;74343:30:0;74323:51;;74224:161;74398:1;:7;;74403:2;74398:7;;:18;;;;;74409:1;:7;;74414:2;74409:7;;74398:18;74394:100;;;-1:-1:-1;74448:1:0;;-1:-1:-1;74452:30:0;74432:51;;74394:100;74605:24;;;74588:14;74605:24;;;;;;;;;26802:25:1;;;26875:4;26863:17;;26843:18;;;26836:45;;;;26897:18;;;26890:34;;;26940:18;;;26933:34;;;74605:24:0;;26774:19:1;;74605:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;74605:24:0;;;;;;-1:-1:-1;;74643:20:0;;;74639:101;;74695:1;74699:29;74679:50;;;;;;;74639:101;74758:6;-1:-1:-1;74766:20:0;;-1:-1:-1;73191:1603:0;;;;;;;;:::o;6316:203::-;6489:13;;;;;;;;;;;;;;;;;;6371:11;;6418:4;6410:12;;;;;6489:22;;;;;;:::i;:::-;;;;;;;;6316:203;-1:-1:-1;;;6316:203:0:o;83587:1388::-;83653:4;83790:19;;;:12;;;:19;;;;;;83824:15;;83820:1149;;84193:21;84217:14;84230:1;84217:10;:14;:::i;:::-;84265:18;;84193:38;;-1:-1:-1;84245:17:0;;84265:22;;84286:1;;84265:22;:::i;:::-;84245:42;;84319:13;84306:9;:26;84302:398;;84352:17;84372:3;:11;;84384:9;84372:22;;;;;;;;:::i;:::-;;;;;;;;;84352:42;;84523:9;84494:3;:11;;84506:13;84494:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;84606:23;;;:12;;;:23;;;;;:36;;;84302:398;84778:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;84870:3;:12;;:19;84883:5;84870:19;;;;;;;;;;;84863:26;;;84911:4;84904:11;;;;;;;83820:1149;84953:5;84946:12;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:163:1:-;81:20;;141:10;130:22;;120:33;;110:61;;167:1;164;157:12;182:184;240:6;293:2;281:9;272:7;268:23;264:32;261:52;;;309:1;306;299:12;261:52;332:28;350:9;332:28;:::i;1003:184::-;1055:77;1052:1;1045:88;1152:4;1149:1;1142:15;1176:4;1173:1;1166:15;1192:777;1234:5;1287:3;1280:4;1272:6;1268:17;1264:27;1254:55;;1305:1;1302;1295:12;1254:55;1341:6;1328:20;1367:18;1404:2;1400;1397:10;1394:36;;;1410:18;;:::i;:::-;1544:2;1538:9;1606:4;1598:13;;1449:66;1594:22;;;1618:2;1590:31;1586:40;1574:53;;;1642:18;;;1662:22;;;1639:46;1636:72;;;1688:18;;:::i;:::-;1728:10;1724:2;1717:22;1763:2;1755:6;1748:18;1809:3;1802:4;1797:2;1789:6;1785:15;1781:26;1778:35;1775:55;;;1826:1;1823;1816:12;1775:55;1890:2;1883:4;1875:6;1871:17;1864:4;1856:6;1852:17;1839:54;1937:1;1930:4;1925:2;1917:6;1913:15;1909:26;1902:37;1957:6;1948:15;;;;;;1192:777;;;;:::o;1974:320::-;2042:6;2095:2;2083:9;2074:7;2070:23;2066:32;2063:52;;;2111:1;2108;2101:12;2063:52;2151:9;2138:23;2184:18;2176:6;2173:30;2170:50;;;2216:1;2213;2206:12;2170:50;2239:49;2280:7;2271:6;2260:9;2256:22;2239:49;:::i;2491:180::-;2550:6;2603:2;2591:9;2582:7;2578:23;2574:32;2571:52;;;2619:1;2616;2609:12;2571:52;-1:-1:-1;2642:23:1;;2491:180;-1:-1:-1;2491:180:1:o;2907:681::-;3078:2;3130:21;;;3200:13;;3103:18;;;3222:22;;;3049:4;;3078:2;3301:15;;;;3275:2;3260:18;;;3049:4;3344:218;3358:6;3355:1;3352:13;3344:218;;;3423:13;;3438:42;3419:62;3407:75;;3537:15;;;;3502:12;;;;3380:1;3373:9;3344:218;;;-1:-1:-1;3579:3:1;;2907:681;-1:-1:-1;;;;;;2907:681:1:o;3593:154::-;3679:42;3672:5;3668:54;3661:5;3658:65;3648:93;;3737:1;3734;3727:12;3752:247;3811:6;3864:2;3852:9;3843:7;3839:23;3835:32;3832:52;;;3880:1;3877;3870:12;3832:52;3919:9;3906:23;3938:31;3963:5;3938:31;:::i;4727:753::-;4838:6;4846;4854;4862;4870;4923:3;4911:9;4902:7;4898:23;4894:33;4891:53;;;4940:1;4937;4930:12;4891:53;4963:28;4981:9;4963:28;:::i;:::-;4953:38;;5038:2;5027:9;5023:18;5010:32;5000:42;;5061:37;5094:2;5083:9;5079:18;5061:37;:::i;:::-;5051:47;;5149:2;5138:9;5134:18;5121:32;5172:18;5213:2;5205:6;5202:14;5199:34;;;5229:1;5226;5219:12;5199:34;5252:49;5293:7;5284:6;5273:9;5269:22;5252:49;:::i;:::-;5242:59;;5354:3;5343:9;5339:19;5326:33;5310:49;;5384:2;5374:8;5371:16;5368:36;;;5400:1;5397;5390:12;5368:36;;5423:51;5466:7;5455:8;5444:9;5440:24;5423:51;:::i;:::-;5413:61;;;4727:753;;;;;;;;:::o;5737:256::-;5803:6;5811;5864:2;5852:9;5843:7;5839:23;5835:32;5832:52;;;5880:1;5877;5870:12;5832:52;5903:28;5921:9;5903:28;:::i;:::-;5893:38;;5950:37;5983:2;5972:9;5968:18;5950:37;:::i;:::-;5940:47;;5737:256;;;;;:::o;7489:251::-;7559:6;7612:2;7600:9;7591:7;7587:23;7583:32;7580:52;;;7628:1;7625;7618:12;7580:52;7660:9;7654:16;7679:31;7704:5;7679:31;:::i;9720:184::-;9772:77;9769:1;9762:88;9869:4;9866:1;9859:15;9893:4;9890:1;9883:15;9909:172;9976:10;10006;;;10018;;;10002:27;;10041:11;;;10038:37;;;10055:18;;:::i;10086:250::-;10171:1;10181:113;10195:6;10192:1;10189:13;10181:113;;;10271:11;;;10265:18;10252:11;;;10245:39;10217:2;10210:10;10181:113;;;-1:-1:-1;;10328:1:1;10310:16;;10303:27;10086:250::o;10341:329::-;10382:3;10420:5;10414:12;10447:6;10442:3;10435:19;10463:76;10532:6;10525:4;10520:3;10516:14;10509:4;10502:5;10498:16;10463:76;:::i;:::-;10584:2;10572:15;10589:66;10568:88;10559:98;;;;10659:4;10555:109;;10341:329;-1:-1:-1;;10341:329:1:o;10675:377::-;10868:2;10857:9;10850:21;10831:4;10894:44;10934:2;10923:9;10919:18;10911:6;10894:44;:::i;:::-;10986:9;10978:6;10974:22;10969:2;10958:9;10954:18;10947:50;11014:32;11039:6;11031;11014:32;:::i;11414:184::-;11466:77;11463:1;11456:88;11563:4;11560:1;11553:15;11587:4;11584:1;11577:15;11959:128;12026:9;;;12047:11;;;12044:37;;;12061:18;;:::i;12783:125::-;12848:9;;;12869:10;;;12866:36;;;12882:18;;:::i;13611:217::-;13758:2;13747:9;13740:21;13721:4;13778:44;13818:2;13807:9;13803:18;13795:6;13778:44;:::i;15012:188::-;15079:26;15125:10;;;15137;;;15121:27;;15160:11;;;15157:37;;;15174:18;;:::i;15205:184::-;15257:77;15254:1;15247:88;15354:4;15351:1;15344:15;15378:4;15375:1;15368:15;18290:1031;18589:3;18617:66;18726:2;18717:6;18712:3;18708:16;18704:25;18699:3;18692:38;18781:2;18772:6;18767:3;18763:16;18759:25;18755:1;18750:3;18746:11;18739:46;18836:2;18827:6;18822:3;18818:16;18814:25;18810:1;18805:3;18801:11;18794:46;;18869:6;18863:13;18885:74;18952:6;18948:1;18943:3;18939:11;18932:4;18924:6;18920:17;18885:74;:::i;:::-;19019:13;;18978:16;;;;19041:75;19019:13;19103:1;19095:10;;19088:4;19076:17;;19041:75;:::i;:::-;19177:13;;19135:17;;;19199:75;19177:13;19261:1;19253:10;;19246:4;19234:17;;19199:75;:::i;:::-;19294:17;19313:1;19290:25;;18290:1031;-1:-1:-1;;;;;;;;18290:1031:1:o;19326:184::-;19378:77;19375:1;19368:88;19475:4;19472:1;19465:15;19499:4;19496:1;19489:15;19515:482;19604:1;19647:5;19604:1;19661:330;19682:7;19672:8;19669:21;19661:330;;;19801:4;19733:66;19729:77;19723:4;19720:87;19717:113;;;19810:18;;:::i;:::-;19860:7;19850:8;19846:22;19843:55;;;19880:16;;;;19843:55;19959:22;;;;19919:15;;;;19661:330;;;19665:3;19515:482;;;;;:::o;20002:866::-;20051:5;20081:8;20071:80;;-1:-1:-1;20122:1:1;20136:5;;20071:80;20170:4;20160:76;;-1:-1:-1;20207:1:1;20221:5;;20160:76;20252:4;20270:1;20265:59;;;;20338:1;20333:130;;;;20245:218;;20265:59;20295:1;20286:10;;20309:5;;;20333:130;20370:3;20360:8;20357:17;20354:43;;;20377:18;;:::i;:::-;-1:-1:-1;;20433:1:1;20419:16;;20448:5;;20245:218;;20547:2;20537:8;20534:16;20528:3;20522:4;20519:13;20515:36;20509:2;20499:8;20496:16;20491:2;20485:4;20482:12;20478:35;20475:77;20472:159;;;-1:-1:-1;20584:19:1;;;20616:5;;20472:159;20663:34;20688:8;20682:4;20663:34;:::i;:::-;20793:6;20725:66;20721:79;20712:7;20709:92;20706:118;;;20804:18;;:::i;:::-;20842:20;;20002:866;-1:-1:-1;;;20002:866:1:o;20873:131::-;20933:5;20962:36;20989:8;20983:4;20962:36;:::i;22801:225::-;22905:4;22884:12;;;22898;;;22880:31;22931:22;;;;22972:24;;;22962:58;;23000:18;;:::i;23031:151::-;23121:4;23114:12;;;23100;;;23096:31;;23139:14;;23136:40;;;23156:18;;:::i;25179:1391::-;25901:34;25889:47;;25966:23;25961:2;25952:12;;25945:45;26009:66;26113:3;26109:16;;;26105:25;;26100:2;26091:12;;26084:47;26150:17;26192:2;26183:12;;26176:24;;;26234:16;;;26230:25;;26225:2;26216:12;;26209:47;26286:34;26281:2;26272:12;;26265:56;26352:3;26346;26337:13;;26330:26;26391:16;;;26387:25;;26381:3;26372:13;;26365:48;26438:3;26429:13;;26422:25;26482:16;;;26478:25;26472:3;26463:13;;26456:48;25137:3;26559;26550:13;;25125:16;-1:-1:-1;25157:11:1;;;26520:44;25060:114;26978:184;27030:77;27027:1;27020:88;27127:4;27124:1;27117:15;27151:4;27148:1;27141:15","abiDefinition":[{"inputs":[{"internalType":"uint32","name":"_domain","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"AttestationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"CorrectFraudReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":true,"internalType":"uint32","name":"nonce","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"destination","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"tips","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"Dispatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"FraudAttestation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":true,"internalType":"address","name":"reporter","type":"address"}],"name":"GuardSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"IncorrectReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"notaryManager","type":"address"}],"name":"NewNotaryManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":true,"internalType":"address","name":"reporter","type":"address"}],"name":"NotarySlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"MAX_MESSAGE_BODY_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SYNAPSE_DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allGuards","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allNotaries","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"bytes32","name":"_recipient","type":"bytes32"},{"internalType":"uint32","name":"_optimisticSeconds","type":"uint32"},{"internalType":"bytes","name":"_tips","type":"bytes"},{"internalType":"bytes","name":"_messageBody","type":"bytes"}],"name":"dispatch","outputs":[{"internalType":"uint32","name":"messageNonce","type":"uint32"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getGuard","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_nonce","type":"uint32"}],"name":"getHistoricalRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getNotary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract INotaryManager","name":"_notaryManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"nonce","outputs":[{"internalType":"uint32","name":"latestNonce","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notariesAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notaryManager","outputs":[{"internalType":"contract INotaryManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"root","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_notary","type":"address"}],"name":"setNotary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_notaryManager","type":"address"}],"name":"setNotaryManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISystemRouter","name":"_systemRouter","type":"address"}],"name":"setSystemRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_attestation","type":"bytes"}],"name":"submitAttestation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_report","type":"bytes"}],"name":"submitReport","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"suggestAttestation","outputs":[{"internalType":"uint32","name":"latestNonce","type":"uint32"},{"internalType":"bytes32","name":"latestRoot","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemRouter","outputs":[{"internalType":"contract ISystemRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"events":{"AttestationAccepted(address,bytes)":{"notice":"Emitted when an attestation is submitted to AttestationHub."},"CorrectFraudReport(address,bytes)":{"notice":"Emitted when a correct report on a fraud attestation is submitted."},"Dispatch(bytes32,uint32,uint32,bytes,bytes)":{"notice":"Emitted when a new message is dispatched"},"FraudAttestation(address,bytes)":{"notice":"Emitted when proof of an fraud attestation is submitted."},"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."},"GuardSlashed(address,address)":{"notice":"Emitted when the Guard is slashed (should be paired with IncorrectReport event)"},"IncorrectReport(address,bytes)":{"notice":"Emitted when proof of an incorrect report is submitted."},"NewNotaryManager(address)":{"notice":"Emitted when the NotaryManager contract is changed"},"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."},"NotarySlashed(address,address,address)":{"notice":"Emitted when the Notary is slashed (should be paired with FraudAttestation event)"}},"kind":"user","methods":{"allGuards()":{"notice":"Returns addresses of all Guards."},"allNotaries()":{"notice":"Returns addresses of all Notaries."},"dispatch(uint32,bytes32,uint32,bytes,bytes)":{"notice":"Dispatch the message to the destination domain \u0026 recipient"},"getGuard(uint256)":{"notice":"Returns i-th Guard. O(1)"},"getHistoricalRoot(uint32,uint32)":{"notice":"Returns a historical merkle root for the given destination. Note: signing the attestation with the given historical root will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain)."},"getNotary(uint256)":{"notice":"Returns i-th Notary. O(1)"},"guardsAmount()":{"notice":"Returns amount of active guards. O(1)"},"nonce(uint32)":{"notice":"Returns nonce of the last inserted Merkle root for the given destination, which is also the number of inserted leaves in the destination merkle tree (current index)."},"notariesAmount()":{"notice":"Returns amount of active notaries. O(1)"},"root(uint32)":{"notice":"Calculates and returns tree's current root for the given destination."},"setNotary(address)":{"notice":"Set a new Notary"},"setNotaryManager(address)":{"notice":"Set a new NotaryManager contract"},"submitAttestation(bytes)":{"notice":"Called by the external agent. Submits the signed attestation for handling."},"submitReport(bytes)":{"notice":"Called by the external agent. Submits the signed report for handling."},"suggestAttestation(uint32)":{"notice":"Suggest attestation for the off-chain actors to sign for a specific destination. Note: signing the suggested attestation will will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain)."}},"version":1},"developerDoc":{"kind":"dev","methods":{"allGuards()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"allNotaries()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"dispatch(uint32,bytes32,uint32,bytes,bytes)":{"details":"Format the message, insert its hash into Merkle tree, enqueue the new Merkle root, and emit `Dispatch` event with message information.","params":{"_destination":"Domain of destination chain","_messageBody":"Raw bytes content of message","_recipient":"Address of recipient on destination chain as bytes32"}},"getGuard(uint256)":{"details":"Will revert if index is out of range"},"getHistoricalRoot(uint32,uint32)":{"params":{"_destination":"Destination domain","_nonce":"Historical nonce"},"returns":{"_0":"Root for destination's merkle tree right after message to `_destination` with `nonce = _nonce` was dispatched."}},"getNotary(uint256)":{"details":"Will revert if index is out of range"},"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Should be impossible to renounce ownership; we override OpenZeppelin OwnableUpgradeable's implementation of renounceOwnership to make it a no-op"},"setNotary(address)":{"details":"To be set when rotating Notary after Fraud","params":{"_notary":"the new Notary"}},"setNotaryManager(address)":{"details":"Origin(s) will initially be initialized using a trusted NotaryManager contract; we will progressively decentralize by swapping the trusted contract with a new implementation that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation","params":{"_notaryManager":"the new NotaryManager contract"}},"submitAttestation(bytes)":{"details":"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.","params":{"_attestation":"Payload with Attestation data and signature (see Attestation.sol)"},"returns":{"_0":"TRUE if Attestation was handled correctly."}},"submitReport(bytes)":{"details":"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.","params":{"_report":"Payload with Report data and signature"},"returns":{"_0":"TRUE if Report was handled correctly."}},"suggestAttestation(uint32)":{"details":"If no messages have been sent, following values are returned: - nonce = 0 - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757 Which is the merkle root for an empty merkle tree.","returns":{"latestNonce":"Current nonce","latestRoot":" Current merkle root"}},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_domain\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"AttestationAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"CorrectFraudReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"destination\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"tips\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"Dispatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"FraudAttestation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"GuardSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"IncorrectReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notaryManager\",\"type\":\"address\"}],\"name\":\"NewNotaryManager\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"NotarySlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_MESSAGE_BODY_BYTES\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SYNAPSE_DOMAIN\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allGuards\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allNotaries\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"_recipient\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_optimisticSeconds\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"_tips\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_messageBody\",\"type\":\"bytes\"}],\"name\":\"dispatch\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"messageNonce\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getGuard\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_nonce\",\"type\":\"uint32\"}],\"name\":\"getHistoricalRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getNotary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardsAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract INotaryManager\",\"name\":\"_notaryManager\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"latestNonce\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notariesAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notaryManager\",\"outputs\":[{\"internalType\":\"contract INotaryManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"root\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_notary\",\"type\":\"address\"}],\"name\":\"setNotary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_notaryManager\",\"type\":\"address\"}],\"name\":\"setNotaryManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ISystemRouter\",\"name\":\"_systemRouter\",\"type\":\"address\"}],\"name\":\"setSystemRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_attestation\",\"type\":\"bytes\"}],\"name\":\"submitAttestation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_report\",\"type\":\"bytes\"}],\"name\":\"submitReport\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"suggestAttestation\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"latestNonce\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"systemRouter\",\"outputs\":[{\"internalType\":\"contract ISystemRouter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allGuards()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"allNotaries()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"dispatch(uint32,bytes32,uint32,bytes,bytes)\":{\"details\":\"Format the message, insert its hash into Merkle tree, enqueue the new Merkle root, and emit `Dispatch` event with message information.\",\"params\":{\"_destination\":\"Domain of destination chain\",\"_messageBody\":\"Raw bytes content of message\",\"_recipient\":\"Address of recipient on destination chain as bytes32\"}},\"getGuard(uint256)\":{\"details\":\"Will revert if index is out of range\"},\"getHistoricalRoot(uint32,uint32)\":{\"params\":{\"_destination\":\"Destination domain\",\"_nonce\":\"Historical nonce\"},\"returns\":{\"_0\":\"Root for destination's merkle tree right after message to `_destination` with `nonce = _nonce` was dispatched.\"}},\"getNotary(uint256)\":{\"details\":\"Will revert if index is out of range\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Should be impossible to renounce ownership; we override OpenZeppelin OwnableUpgradeable's implementation of renounceOwnership to make it a no-op\"},\"setNotary(address)\":{\"details\":\"To be set when rotating Notary after Fraud\",\"params\":{\"_notary\":\"the new Notary\"}},\"setNotaryManager(address)\":{\"details\":\"Origin(s) will initially be initialized using a trusted NotaryManager contract; we will progressively decentralize by swapping the trusted contract with a new implementation that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\",\"params\":{\"_notaryManager\":\"the new NotaryManager contract\"}},\"submitAttestation(bytes)\":{\"details\":\"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.\",\"params\":{\"_attestation\":\"Payload with Attestation data and signature (see Attestation.sol)\"},\"returns\":{\"_0\":\"TRUE if Attestation was handled correctly.\"}},\"submitReport(bytes)\":{\"details\":\"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.\",\"params\":{\"_report\":\"Payload with Report data and signature\"},\"returns\":{\"_0\":\"TRUE if Report was handled correctly.\"}},\"suggestAttestation(uint32)\":{\"details\":\"If no messages have been sent, following values are returned: - nonce = 0 - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757 Which is the merkle root for an empty merkle tree.\",\"returns\":{\"latestNonce\":\"Current nonce\",\"latestRoot\":\" Current merkle root\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"events\":{\"AttestationAccepted(address,bytes)\":{\"notice\":\"Emitted when an attestation is submitted to AttestationHub.\"},\"CorrectFraudReport(address,bytes)\":{\"notice\":\"Emitted when a correct report on a fraud attestation is submitted.\"},\"Dispatch(bytes32,uint32,uint32,bytes,bytes)\":{\"notice\":\"Emitted when a new message is dispatched\"},\"FraudAttestation(address,bytes)\":{\"notice\":\"Emitted when proof of an fraud attestation is submitted.\"},\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"},\"GuardSlashed(address,address)\":{\"notice\":\"Emitted when the Guard is slashed (should be paired with IncorrectReport event)\"},\"IncorrectReport(address,bytes)\":{\"notice\":\"Emitted when proof of an incorrect report is submitted.\"},\"NewNotaryManager(address)\":{\"notice\":\"Emitted when the NotaryManager contract is changed\"},\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"},\"NotarySlashed(address,address,address)\":{\"notice\":\"Emitted when the Notary is slashed (should be paired with FraudAttestation event)\"}},\"kind\":\"user\",\"methods\":{\"allGuards()\":{\"notice\":\"Returns addresses of all Guards.\"},\"allNotaries()\":{\"notice\":\"Returns addresses of all Notaries.\"},\"dispatch(uint32,bytes32,uint32,bytes,bytes)\":{\"notice\":\"Dispatch the message to the destination domain \u0026 recipient\"},\"getGuard(uint256)\":{\"notice\":\"Returns i-th Guard. O(1)\"},\"getHistoricalRoot(uint32,uint32)\":{\"notice\":\"Returns a historical merkle root for the given destination. Note: signing the attestation with the given historical root will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain).\"},\"getNotary(uint256)\":{\"notice\":\"Returns i-th Notary. O(1)\"},\"guardsAmount()\":{\"notice\":\"Returns amount of active guards. O(1)\"},\"nonce(uint32)\":{\"notice\":\"Returns nonce of the last inserted Merkle root for the given destination, which is also the number of inserted leaves in the destination merkle tree (current index).\"},\"notariesAmount()\":{\"notice\":\"Returns amount of active notaries. O(1)\"},\"root(uint32)\":{\"notice\":\"Calculates and returns tree's current root for the given destination.\"},\"setNotary(address)\":{\"notice\":\"Set a new Notary\"},\"setNotaryManager(address)\":{\"notice\":\"Set a new NotaryManager contract\"},\"submitAttestation(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed attestation for handling.\"},\"submitReport(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed report for handling.\"},\"suggestAttestation(uint32)\":{\"notice\":\"Suggest attestation for the off-chain actors to sign for a specific destination. Note: signing the suggested attestation will will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain).\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Origin\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"MAX_MESSAGE_BODY_BYTES()":"522ae002","SYNAPSE_DOMAIN()":"bf61e67e","VERSION()":"ffa1ad74","allGuards()":"9fe03fa2","allNotaries()":"9817e315","dispatch(uint32,bytes32,uint32,bytes,bytes)":"f7560e40","getGuard(uint256)":"629ddf69","getHistoricalRoot(uint32,uint32)":"f94adcb4","getNotary(uint256)":"c07dc7f5","guardsAmount()":"246c2449","initialize(address)":"c4d66de8","localDomain()":"8d3638f4","nonce(uint32)":"141c4985","notariesAmount()":"8e62e9ef","notaryManager()":"f85b597e","owner()":"8da5cb5b","renounceOwnership()":"715018a6","root(uint32)":"e65b6bd4","setNotary(address)":"a394a0e6","setNotaryManager(address)":"a340abc1","setSystemRouter(address)":"fbde22f7","submitAttestation(bytes)":"f646a512","submitReport(bytes)":"5815869d","suggestAttestation(uint32)":"dd0f1f74","systemRouter()":"529d1549","transferOwnership(address)":"f2fde38b"}},"solidity/NotaryManager.sol:OriginEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":true,"internalType":"uint32","name":"nonce","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"destination","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"tips","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"Dispatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":true,"internalType":"address","name":"reporter","type":"address"}],"name":"GuardSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"notaryManager","type":"address"}],"name":"NewNotaryManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":true,"internalType":"address","name":"reporter","type":"address"}],"name":"NotarySlashed","type":"event"}],"userDoc":{"events":{"Dispatch(bytes32,uint32,uint32,bytes,bytes)":{"notice":"Emitted when a new message is dispatched"},"GuardSlashed(address,address)":{"notice":"Emitted when the Guard is slashed (should be paired with IncorrectReport event)"},"NewNotaryManager(address)":{"notice":"Emitted when the NotaryManager contract is changed"},"NotarySlashed(address,address,address)":{"notice":"Emitted when the Notary is slashed (should be paired with FraudAttestation event)"}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"Dispatch(bytes32,uint32,uint32,bytes,bytes)":{"params":{"destination":"Destination domain","message":"Raw bytes of message","messageHash":"Hash of message; the leaf inserted to the Merkle tree        for the message","nonce":"Nonce of sent message (starts from 1)","tips":"Tips paid for the remote off-chain agents"}},"GuardSlashed(address,address)":{"params":{"guard":"The address of the guard that signed the incorrect report","reporter":"The address of the entity that reported the guard misbehavior"}},"NewNotaryManager(address)":{"params":{"notaryManager":"The address of the new notaryManager"}},"NotarySlashed(address,address,address)":{"params":{"guard":"The address of the guard that signed the fraud report","notary":"The address of the notary","reporter":"The address of the entity that reported the notary misbehavior"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"destination\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"tips\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"Dispatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"GuardSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notaryManager\",\"type\":\"address\"}],\"name\":\"NewNotaryManager\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"reporter\",\"type\":\"address\"}],\"name\":\"NotarySlashed\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"Dispatch(bytes32,uint32,uint32,bytes,bytes)\":{\"params\":{\"destination\":\"Destination domain\",\"message\":\"Raw bytes of message\",\"messageHash\":\"Hash of message; the leaf inserted to the Merkle tree        for the message\",\"nonce\":\"Nonce of sent message (starts from 1)\",\"tips\":\"Tips paid for the remote off-chain agents\"}},\"GuardSlashed(address,address)\":{\"params\":{\"guard\":\"The address of the guard that signed the incorrect report\",\"reporter\":\"The address of the entity that reported the guard misbehavior\"}},\"NewNotaryManager(address)\":{\"params\":{\"notaryManager\":\"The address of the new notaryManager\"}},\"NotarySlashed(address,address,address)\":{\"params\":{\"guard\":\"The address of the guard that signed the fraud report\",\"notary\":\"The address of the notary\",\"reporter\":\"The address of the entity that reported the notary misbehavior\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"Dispatch(bytes32,uint32,uint32,bytes,bytes)\":{\"notice\":\"Emitted when a new message is dispatched\"},\"GuardSlashed(address,address)\":{\"notice\":\"Emitted when the Guard is slashed (should be paired with IncorrectReport event)\"},\"NewNotaryManager(address)\":{\"notice\":\"Emitted when the NotaryManager contract is changed\"},\"NotarySlashed(address,address,address)\":{\"notice\":\"Emitted when the Notary is slashed (should be paired with FraudAttestation event)\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"OriginEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:OriginHub":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"AttestationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"CorrectFraudReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"FraudAttestation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"IncorrectReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"},{"inputs":[],"name":"allGuards","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allNotaries","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getGuard","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"},{"internalType":"uint32","name":"_nonce","type":"uint32"}],"name":"getHistoricalRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getNotary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"nonce","outputs":[{"internalType":"uint32","name":"latestNonce","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notariesAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"root","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_attestation","type":"bytes"}],"name":"submitAttestation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_report","type":"bytes"}],"name":"submitReport","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_destination","type":"uint32"}],"name":"suggestAttestation","outputs":[{"internalType":"uint32","name":"latestNonce","type":"uint32"},{"internalType":"bytes32","name":"latestRoot","type":"bytes32"}],"stateMutability":"view","type":"function"}],"userDoc":{"events":{"AttestationAccepted(address,bytes)":{"notice":"Emitted when an attestation is submitted to AttestationHub."},"CorrectFraudReport(address,bytes)":{"notice":"Emitted when a correct report on a fraud attestation is submitted."},"FraudAttestation(address,bytes)":{"notice":"Emitted when proof of an fraud attestation is submitted."},"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."},"IncorrectReport(address,bytes)":{"notice":"Emitted when proof of an incorrect report is submitted."},"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{"allGuards()":{"notice":"Returns addresses of all Guards."},"allNotaries()":{"notice":"Returns addresses of all Notaries."},"getGuard(uint256)":{"notice":"Returns i-th Guard. O(1)"},"getHistoricalRoot(uint32,uint32)":{"notice":"Returns a historical merkle root for the given destination. Note: signing the attestation with the given historical root will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain)."},"getNotary(uint256)":{"notice":"Returns i-th Notary. O(1)"},"guardsAmount()":{"notice":"Returns amount of active guards. O(1)"},"nonce(uint32)":{"notice":"Returns nonce of the last inserted Merkle root for the given destination, which is also the number of inserted leaves in the destination merkle tree (current index)."},"notariesAmount()":{"notice":"Returns amount of active notaries. O(1)"},"root(uint32)":{"notice":"Calculates and returns tree's current root for the given destination."},"submitAttestation(bytes)":{"notice":"Called by the external agent. Submits the signed attestation for handling."},"submitReport(bytes)":{"notice":"Called by the external agent. Submits the signed report for handling."},"suggestAttestation(uint32)":{"notice":"Suggest attestation for the off-chain actors to sign for a specific destination. Note: signing the suggested attestation will will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain)."}},"version":1},"developerDoc":{"kind":"dev","methods":{"allGuards()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"allNotaries()":{"details":"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())"},"getGuard(uint256)":{"details":"Will revert if index is out of range"},"getHistoricalRoot(uint32,uint32)":{"params":{"_destination":"Destination domain","_nonce":"Historical nonce"},"returns":{"_0":"Root for destination's merkle tree right after message to `_destination` with `nonce = _nonce` was dispatched."}},"getNotary(uint256)":{"details":"Will revert if index is out of range"},"submitAttestation(bytes)":{"details":"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.","params":{"_attestation":"Payload with Attestation data and signature (see Attestation.sol)"},"returns":{"_0":"TRUE if Attestation was handled correctly."}},"submitReport(bytes)":{"details":"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.","params":{"_report":"Payload with Report data and signature"},"returns":{"_0":"TRUE if Report was handled correctly."}},"suggestAttestation(uint32)":{"details":"If no messages have been sent, following values are returned: - nonce = 0 - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757 Which is the merkle root for an empty merkle tree.","returns":{"latestNonce":"Current nonce","latestRoot":" Current merkle root"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"AttestationAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"CorrectFraudReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"FraudAttestation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"IncorrectReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allGuards\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allNotaries\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getGuard\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_nonce\",\"type\":\"uint32\"}],\"name\":\"getHistoricalRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getNotary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardsAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"latestNonce\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notariesAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"root\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_attestation\",\"type\":\"bytes\"}],\"name\":\"submitAttestation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_report\",\"type\":\"bytes\"}],\"name\":\"submitReport\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_destination\",\"type\":\"uint32\"}],\"name\":\"suggestAttestation\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"latestNonce\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allGuards()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"allNotaries()\":{\"details\":\"This copies storage into memory, so can consume a lof of gas, if amount of notaries is large (see EnumerableSet.values())\"},\"getGuard(uint256)\":{\"details\":\"Will revert if index is out of range\"},\"getHistoricalRoot(uint32,uint32)\":{\"params\":{\"_destination\":\"Destination domain\",\"_nonce\":\"Historical nonce\"},\"returns\":{\"_0\":\"Root for destination's merkle tree right after message to `_destination` with `nonce = _nonce` was dispatched.\"}},\"getNotary(uint256)\":{\"details\":\"Will revert if index is out of range\"},\"submitAttestation(bytes)\":{\"details\":\"Reverts if either of this is true:      - Attestation payload is not properly formatted.      - Attestation signer is not a Notary.\",\"params\":{\"_attestation\":\"Payload with Attestation data and signature (see Attestation.sol)\"},\"returns\":{\"_0\":\"TRUE if Attestation was handled correctly.\"}},\"submitReport(bytes)\":{\"details\":\"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.\",\"params\":{\"_report\":\"Payload with Report data and signature\"},\"returns\":{\"_0\":\"TRUE if Report was handled correctly.\"}},\"suggestAttestation(uint32)\":{\"details\":\"If no messages have been sent, following values are returned: - nonce = 0 - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757 Which is the merkle root for an empty merkle tree.\",\"returns\":{\"latestNonce\":\"Current nonce\",\"latestRoot\":\" Current merkle root\"}}},\"version\":1},\"userdoc\":{\"events\":{\"AttestationAccepted(address,bytes)\":{\"notice\":\"Emitted when an attestation is submitted to AttestationHub.\"},\"CorrectFraudReport(address,bytes)\":{\"notice\":\"Emitted when a correct report on a fraud attestation is submitted.\"},\"FraudAttestation(address,bytes)\":{\"notice\":\"Emitted when proof of an fraud attestation is submitted.\"},\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"},\"IncorrectReport(address,bytes)\":{\"notice\":\"Emitted when proof of an incorrect report is submitted.\"},\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{\"allGuards()\":{\"notice\":\"Returns addresses of all Guards.\"},\"allNotaries()\":{\"notice\":\"Returns addresses of all Notaries.\"},\"getGuard(uint256)\":{\"notice\":\"Returns i-th Guard. O(1)\"},\"getHistoricalRoot(uint32,uint32)\":{\"notice\":\"Returns a historical merkle root for the given destination. Note: signing the attestation with the given historical root will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain).\"},\"getNotary(uint256)\":{\"notice\":\"Returns i-th Notary. O(1)\"},\"guardsAmount()\":{\"notice\":\"Returns amount of active guards. O(1)\"},\"nonce(uint32)\":{\"notice\":\"Returns nonce of the last inserted Merkle root for the given destination, which is also the number of inserted leaves in the destination merkle tree (current index).\"},\"notariesAmount()\":{\"notice\":\"Returns amount of active notaries. O(1)\"},\"root(uint32)\":{\"notice\":\"Calculates and returns tree's current root for the given destination.\"},\"submitAttestation(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed attestation for handling.\"},\"submitReport(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed report for handling.\"},\"suggestAttestation(uint32)\":{\"notice\":\"Suggest attestation for the off-chain actors to sign for a specific destination. Note: signing the suggested attestation will will never lead to slashing of the actor, assuming they have confirmed that the block, where the merkle root was updated, is not subject to reorganization (which is different for every observed chain).\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"OriginHub\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"allGuards()":"9fe03fa2","allNotaries()":"9817e315","getGuard(uint256)":"629ddf69","getHistoricalRoot(uint32,uint32)":"f94adcb4","getNotary(uint256)":"c07dc7f5","guardsAmount()":"246c2449","localDomain()":"8d3638f4","nonce(uint32)":"141c4985","notariesAmount()":"8e62e9ef","root(uint32)":"e65b6bd4","submitAttestation(bytes)":"f646a512","submitReport(bytes)":"5815869d","suggestAttestation(uint32)":"dd0f1f74"}},"solidity/NotaryManager.sol:OriginHubEvents":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"CorrectFraudReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"notary","type":"address"},{"indexed":false,"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"FraudAttestation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guard","type":"address"},{"indexed":false,"internalType":"bytes","name":"report","type":"bytes"}],"name":"IncorrectReport","type":"event"}],"userDoc":{"events":{"CorrectFraudReport(address,bytes)":{"notice":"Emitted when a correct report on a fraud attestation is submitted."},"FraudAttestation(address,bytes)":{"notice":"Emitted when proof of an fraud attestation is submitted."},"IncorrectReport(address,bytes)":{"notice":"Emitted when proof of an incorrect report is submitted."}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"CorrectFraudReport(address,bytes)":{"params":{"guard":"Guard who signed the fraud report","report":"Report data and signature"}},"FraudAttestation(address,bytes)":{"params":{"attestation":"Attestation data and signature","notary":"Notary who signed fraud attestation"}},"IncorrectReport(address,bytes)":{"params":{"guard":"Guard who signed the incorrect report","report":"Report data and signature"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"CorrectFraudReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"attestation\",\"type\":\"bytes\"}],\"name\":\"FraudAttestation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"IncorrectReport\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"CorrectFraudReport(address,bytes)\":{\"params\":{\"guard\":\"Guard who signed the fraud report\",\"report\":\"Report data and signature\"}},\"FraudAttestation(address,bytes)\":{\"params\":{\"attestation\":\"Attestation data and signature\",\"notary\":\"Notary who signed fraud attestation\"}},\"IncorrectReport(address,bytes)\":{\"params\":{\"guard\":\"Guard who signed the incorrect report\",\"report\":\"Report data and signature\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"CorrectFraudReport(address,bytes)\":{\"notice\":\"Emitted when a correct report on a fraud attestation is submitted.\"},\"FraudAttestation(address,bytes)\":{\"notice\":\"Emitted when proof of an fraud attestation is submitted.\"},\"IncorrectReport(address,bytes)\":{\"notice\":\"Emitted when proof of an incorrect report is submitted.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"OriginHubEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:Ownable":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{"constructor":{"details":"Initializes the contract setting the deployer as the initial owner."},"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Initializes the contract setting the deployer as the initial owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Ownable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"owner()":"8da5cb5b","renounceOwnership()":"715018a6","transferOwnership(address)":"f2fde38b"}},"solidity/NotaryManager.sol:OwnableUpgradeable":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"stateVariables":{"__gap":{"details":"This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"stateVariables\":{\"__gap\":{\"details\":\"This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"OwnableUpgradeable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"owner()":"8da5cb5b","renounceOwnership()":"715018a6","transferOwnership(address)":"f2fde38b"}},"solidity/NotaryManager.sol:Report":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208f5f066953ca6a49bcc7f8161c6c5a3727cdff7a8b3f887a1c83e36e76859dd464736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208f5f066953ca6a49bcc7f8161c6c5a3727cdff7a8b3f887a1c83e36e76859dd464736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"55468:10579:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;55468:10579:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"55468:10579:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"OFFSET_FLAG":{"details":"ReportData memory layout [000 .. 001): flag           uint8    1 bytes [001 .. 045): attData        bytes   44 bytes guardSig is Guard's signature on ReportData      Report memory layout [000 .. 001): flag           uint8    1 bytes [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes) [110 .. 175): guardSig       bytes   65 bytes      Unpack attestation field (see Attestation.sol) [000 .. 001): flag           uint8    1 bytes [001 .. 045): attData        bytes   44 bytes [045 .. 110): notarySig      bytes   65 bytes [110 .. 175): guardSig       bytes   65 bytes notarySig is Notary's signature on AttestationData flag + attData = reportData (see above), so      Report memory layout (sliced alternatively) [000 .. 045): reportData     bytes   45 bytes [045 .. 110): notarySig      bytes   65 bytes [110 .. 171): guardSig       bytes   61 bytes"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"OFFSET_FLAG\":{\"details\":\"ReportData memory layout [000 .. 001): flag           uint8    1 bytes [001 .. 045): attData        bytes   44 bytes guardSig is Guard's signature on ReportData      Report memory layout [000 .. 001): flag           uint8    1 bytes [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes) [110 .. 175): guardSig       bytes   65 bytes      Unpack attestation field (see Attestation.sol) [000 .. 001): flag           uint8    1 bytes [001 .. 045): attData        bytes   44 bytes [045 .. 110): notarySig      bytes   65 bytes [110 .. 175): guardSig       bytes   65 bytes notarySig is Notary's signature on AttestationData flag + attData = reportData (see above), so      Report memory layout (sliced alternatively) [000 .. 045): reportData     bytes   45 bytes [045 .. 110): notarySig      bytes   65 bytes [110 .. 171): guardSig       bytes   61 bytes\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Report\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:ReportHub":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"GuardRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":false,"internalType":"address","name":"notary","type":"address"}],"name":"NotaryRemoved","type":"event"},{"inputs":[{"internalType":"bytes","name":"_report","type":"bytes"}],"name":"submitReport","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"events":{"GuardAdded(address)":{"notice":"Emitted when a new Guard is added."},"GuardRemoved(address)":{"notice":"Emitted when a Guard is removed."},"NotaryRemoved(uint32,address)":{"notice":"Emitted when a new Notary is removed."}},"kind":"user","methods":{"submitReport(bytes)":{"notice":"Called by the external agent. Submits the signed report for handling."}},"version":1},"developerDoc":{"kind":"dev","methods":{"submitReport(bytes)":{"details":"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.","params":{"_report":"Payload with Report data and signature"},"returns":{"_0":"TRUE if Report was handled correctly."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guard\",\"type\":\"address\"}],\"name\":\"GuardRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"domain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notary\",\"type\":\"address\"}],\"name\":\"NotaryRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_report\",\"type\":\"bytes\"}],\"name\":\"submitReport\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"submitReport(bytes)\":{\"details\":\"Reverts if either of this is true:      - Report payload is not properly formatted.      - Report signer is not a Guard.      - Reported notary is not a Notary.\",\"params\":{\"_report\":\"Payload with Report data and signature\"},\"returns\":{\"_0\":\"TRUE if Report was handled correctly.\"}}},\"version\":1},\"userdoc\":{\"events\":{\"GuardAdded(address)\":{\"notice\":\"Emitted when a new Guard is added.\"},\"GuardRemoved(address)\":{\"notice\":\"Emitted when a Guard is removed.\"},\"NotaryRemoved(uint32,address)\":{\"notice\":\"Emitted when a new Notary is removed.\"}},\"kind\":\"user\",\"methods\":{\"submitReport(bytes)\":{\"notice\":\"Called by the external agent. Submits the signed report for handling.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"ReportHub\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"submitReport(bytes)":"5815869d"}},"solidity/NotaryManager.sol:Strings":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220de225a65bd3e08f989a9d9a2c8776674788f867189ae1bfb6b9f5cc8d784833464736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220de225a65bd3e08f989a9d9a2c8776674788f867189ae1bfb6b9f5cc8d784833464736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"66156:2235:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;66156:2235:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"66156:2235:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"String operations.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"String operations.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Strings\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:SynapseTypes":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208358f26d3b4408357371738317cd536660abae6a0fb05e42b77baa9a469fabd564736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208358f26d3b4408357371738317cd536660abae6a0fb05e42b77baa9a469fabd564736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"38028:4460:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;38028:4460:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"38028:4460:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"SynapseTypes\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:SystemCall":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202041ebdb46c3ac6fbcaa2b161aba5eeca0dcaeec7918e493454976af27d5822764736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202041ebdb46c3ac6fbcaa2b161aba5eeca0dcaeec7918e493454976af27d5822764736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"160473:8272:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;160473:8272:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"160473:8272:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"OFFSET_CALL_RECIPIENT":{"details":"SystemCall memory layout [000 .. 001): recipient      uint8   1 bytes [001 .. END]: payload        bytes   ? bytes"},"PAYLOAD_MIN_ARGUMENT_WORDS":{"details":"System Router is supposed to modify (rootSubmittedAt, origin, caller) in the given payload, meaning for a valid system call payload there has to exist at least three arguments, occupying at least three words in total."},"SYSTEM_ROUTER":{"details":"Custom address, used for sending and receiving system messages.      Origin is supposed to dispatch messages from SystemRouter      as if they were sent by this address.      Destination is supposed to reroute messages for this address to SystemRouter.      Note: all bits except for lower 20 bytes are set to 1.      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"OFFSET_CALL_RECIPIENT\":{\"details\":\"SystemCall memory layout [000 .. 001): recipient      uint8   1 bytes [001 .. END]: payload        bytes   ? bytes\"},\"PAYLOAD_MIN_ARGUMENT_WORDS\":{\"details\":\"System Router is supposed to modify (rootSubmittedAt, origin, caller) in the given payload, meaning for a valid system call payload there has to exist at least three arguments, occupying at least three words in total.\"},\"SYSTEM_ROUTER\":{\"details\":\"Custom address, used for sending and receiving system messages.      Origin is supposed to dispatch messages from SystemRouter      as if they were sent by this address.      Destination is supposed to reroute messages for this address to SystemRouter.      Note: all bits except for lower 20 bytes are set to 1.      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"SystemCall\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:SystemContract":{"code":"0x","runtime-code":"0x","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"SYNAPSE_DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISystemRouter","name":"_systemRouter","type":"address"}],"name":"setSystemRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"systemRouter","outputs":[{"internalType":"contract ISystemRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Should be impossible to renounce ownership; we override OpenZeppelin OwnableUpgradeable's implementation of renounceOwnership to make it a no-op"},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SYNAPSE_DOMAIN\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ISystemRouter\",\"name\":\"_systemRouter\",\"type\":\"address\"}],\"name\":\"setSystemRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"systemRouter\",\"outputs\":[{\"internalType\":\"contract ISystemRouter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Should be impossible to renounce ownership; we override OpenZeppelin OwnableUpgradeable's implementation of renounceOwnership to make it a no-op\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"SystemContract\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"SYNAPSE_DOMAIN()":"bf61e67e","localDomain()":"8d3638f4","owner()":"8da5cb5b","renounceOwnership()":"715018a6","setSystemRouter(address)":"fbde22f7","systemRouter()":"529d1549","transferOwnership(address)":"f2fde38b"}},"solidity/NotaryManager.sol:Tips":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207dabb4cff61f4e2b918e9e4404e09940513d9e53fe9b25541f1a86caa434b2f264736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207dabb4cff61f4e2b918e9e4404e09940513d9e53fe9b25541f1a86caa434b2f264736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"146708:5503:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;146708:5503:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"146708:5503:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"OFFSET_VERSION":{"details":"Tips memory layout [000 .. 002): version            uint16\t 2 bytes [002 .. 014): notaryTip          uint96\t12 bytes [014 .. 026): broadcasterTip     uint96\t12 bytes [026 .. 038): proverTip          uint96\t12 bytes [038 .. 050): executorTip        uint96\t12 bytes"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"OFFSET_VERSION\":{\"details\":\"Tips memory layout [000 .. 002): version            uint16\\t 2 bytes [002 .. 014): notaryTip          uint96\\t12 bytes [014 .. 026): broadcasterTip     uint96\\t12 bytes [026 .. 038): proverTip          uint96\\t12 bytes [038 .. 050): executorTip        uint96\\t12 bytes\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Tips\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:TypeCasts":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208006a080854c23bb5cd0c84ae5267d3492bb94c8315519b99288619f6344d27264736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208006a080854c23bb5cd0c84ae5267d3492bb94c8315519b99288619f6344d27264736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"139475:1110:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;139475:1110:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"139475:1110:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"TypeCasts\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{}},"solidity/NotaryManager.sol:TypedMemView":{"code":"0x6101f061003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100ad5760003560e01c806397b8ad4a11610080578063eb74062811610065578063eb740628146100f8578063f26be3fc14610100578063fb734584146100f857600080fd5b806397b8ad4a146100cd578063b602d173146100e557600080fd5b806310153fce146100b25780631136e7ea146100cd57806313090c5a146100d55780631bfe17ce146100dd575b600080fd5b6100ba602881565b6040519081526020015b60405180910390f35b6100ba601881565b6100ba610158565b6100ba610172565b6100ba6bffffffffffffffffffffffff81565b6100ba606081565b6101277fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000081565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000090911681526020016100c4565b606061016581601861017a565b61016f919061017a565b81565b61016f606060185b808201808211156101b4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea2646970667358221220840217a5bfcbef5d6a589af8187c9b7dbf354293f65e9a5e57ce3d1b7ac3286464736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600436106100ad5760003560e01c806397b8ad4a11610080578063eb74062811610065578063eb740628146100f8578063f26be3fc14610100578063fb734584146100f857600080fd5b806397b8ad4a146100cd578063b602d173146100e557600080fd5b806310153fce146100b25780631136e7ea146100cd57806313090c5a146100d55780631bfe17ce146100dd575b600080fd5b6100ba602881565b6040519081526020015b60405180910390f35b6100ba601881565b6100ba610158565b6100ba610172565b6100ba6bffffffffffffffffffffffff81565b6100ba606081565b6101277fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000081565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000090911681526020016100c4565b606061016581601861017a565b61016f919061017a565b81565b61016f606060185b808201808211156101b4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea2646970667358221220840217a5bfcbef5d6a589af8187c9b7dbf354293f65e9a5e57ce3d1b7ac3286464736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"2518:35508:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;2518:35508:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"2518:35508:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5444:38;;5480:2;5444:38;;;;;168:25:1;;;156:2;141:18;5444:38:0;;;;;;;;5701:46;;5611:2;5701:46;;5838:57;;;:::i;5759:56::-;;;:::i;5961:59::-;;6004:16;5961:59;;5531:37;;5566:2;5531:37;;5032:94;;;;;;;;388:66:1;376:79;;;358:98;;346:2;331:18;5032:94:0;204:258:1;5838:57:0;5523:2;5795:20;5523:2;5611;5795:20;:::i;:::-;5875;;;;:::i;:::-;5838:57;:::o;5759:56::-;5795:20;5566:2;5611;467:279:1;532:9;;;553:10;;;550:190;;;596:77;593:1;586:88;697:4;694:1;687:15;725:4;722:1;715:15;550:190;467:279;;;;:::o","abiDefinition":[{"inputs":[],"name":"BITS_EMPTY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BITS_LEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BITS_LOC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BITS_TYPE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOW_96_BITS_MASK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NULL","outputs":[{"internalType":"bytes29","name":"","type":"bytes29"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHIFT_LEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHIFT_LOC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHIFT_TYPE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"stateVariables":{"BITS_TYPE":{"details":"Memory layout for bytes29 [000..005)   type     5 bytes    Type flag for the pointer [005..017)   loc     12 bytes    Memory address of underlying bytes [017..029)   len     12 bytes    Length of underlying bytes [029..032)   empty    3 bytes    Not used"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BITS_EMPTY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BITS_LEN\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BITS_LOC\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BITS_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LOW_96_BITS_MASK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NULL\",\"outputs\":[{\"internalType\":\"bytes29\",\"name\":\"\",\"type\":\"bytes29\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SHIFT_LEN\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SHIFT_LOC\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SHIFT_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"BITS_TYPE\":{\"details\":\"Memory layout for bytes29 [000..005)   type     5 bytes    Type flag for the pointer [005..017)   loc     12 bytes    Memory address of underlying bytes [017..029)   len     12 bytes    Length of underlying bytes [029..032)   empty    3 bytes    Not used\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"TypedMemView\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"BITS_EMPTY()":"97b8ad4a","BITS_LEN()":"eb740628","BITS_LOC()":"fb734584","BITS_TYPE()":"10153fce","LOW_96_BITS_MASK()":"b602d173","NULL()":"f26be3fc","SHIFT_LEN()":"1136e7ea","SHIFT_LOC()":"1bfe17ce","SHIFT_TYPE()":"13090c5a"}},"solidity/NotaryManager.sol:Version0":{"code":"0x6080604052348015600f57600080fd5b5060808061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ffa1ad7414602d575b600080fd5b6034600081565b60405160ff909116815260200160405180910390f3fea26469706673582212204c7725719be31693a34c6428fac6857de9517ef597d9ebf9f5acdaca3686328d64736f6c63430008110033","runtime-code":"0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063ffa1ad7414602d575b600080fd5b6034600081565b60405160ff909116815260200160405180910390f3fea26469706673582212204c7725719be31693a34c6428fac6857de9517ef597d9ebf9f5acdaca3686328d64736f6c63430008110033","info":{"source":"pragma solidity 0.8.17;\n\n\ninterface INotaryManager {\n    function slashNotary(address payable _reporter) external;\n\n    function notary() external view returns (address);\n}\n\nabstract contract DomainContext {\n    /**\n     * @notice Ensures that a domain matches the local domain.\n     */\n    modifier onlyLocalDomain(uint32 _domain) {\n        require(_domain == _localDomain(), \"!localDomain\");\n        _;\n    }\n\n    function localDomain() external view returns (uint32) {\n        return _localDomain();\n    }\n\n    function _localDomain() internal view virtual returns (uint32);\n}\n\ncontract LocalDomainContext is DomainContext {\n    uint32 private immutable __localDomain;\n\n    constructor(uint32 localDomain_) {\n        __localDomain = localDomain_;\n    }\n\n    function _localDomain() internal view override returns (uint32) {\n        return __localDomain;\n    }\n}\n\nabstract contract OriginEvents {\n    /**\n     * @notice Emitted when a new message is dispatched\n     * @param messageHash Hash of message; the leaf inserted to the Merkle tree\n     *        for the message\n     * @param nonce Nonce of sent message (starts from 1)\n     * @param destination Destination domain\n     * @param tips Tips paid for the remote off-chain agents\n     * @param message Raw bytes of message\n     */\n    event Dispatch(\n        bytes32 indexed messageHash,\n        uint32 indexed nonce,\n        uint32 indexed destination,\n        bytes tips,\n        bytes message\n    );\n\n    /**\n     * @notice Emitted when the Guard is slashed\n     * (should be paired with IncorrectReport event)\n     * @param guard     The address of the guard that signed the incorrect report\n     * @param reporter  The address of the entity that reported the guard misbehavior\n     */\n    event GuardSlashed(address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the Notary is slashed\n     * (should be paired with FraudAttestation event)\n     * @param notary    The address of the notary\n     * @param guard     The address of the guard that signed the fraud report\n     * @param reporter  The address of the entity that reported the notary misbehavior\n     */\n    event NotarySlashed(address indexed notary, address indexed guard, address indexed reporter);\n\n    /**\n     * @notice Emitted when the NotaryManager contract is changed\n     * @param notaryManager The address of the new notaryManager\n     */\n    event NewNotaryManager(address notaryManager);\n}\n\ncontract Version0 {\n    uint8 public constant VERSION = 0;\n}\n\nlibrary TypedMemView {\n    // Why does this exist?\n    // the solidity `bytes memory` type has a few weaknesses.\n    // 1. You can't index ranges effectively\n    // 2. You can't slice without copying\n    // 3. The underlying data may represent any type\n    // 4. Solidity never deallocates memory, and memory costs grow\n    //    superlinearly\n\n    // By using a memory view instead of a `bytes memory` we get the following\n    // advantages:\n    // 1. Slices are done on the stack, by manipulating the pointer\n    // 2. We can index arbitrary ranges and quickly convert them to stack types\n    // 3. We can insert type info into the pointer, and typecheck at runtime\n\n    // This makes `TypedMemView` a useful tool for efficient zero-copy\n    // algorithms.\n\n    // Why bytes29?\n    // We want to avoid confusion between views, digests, and other common\n    // types so we chose a large and uncommonly used odd number of bytes\n    //\n    // Note that while bytes are left-aligned in a word, integers and addresses\n    // are right-aligned. This means when working in assembly we have to\n    // account for the 3 unused bytes on the righthand side\n    //\n    // First 5 bytes are a type flag.\n    // - ff_ffff_fffe is reserved for unknown type.\n    // - ff_ffff_ffff is reserved for invalid types/errors.\n    // next 12 are memory address\n    // next 12 are len\n    // bottom 3 bytes are empty\n\n    // Assumptions:\n    // - non-modification of memory.\n    // - No Solidity updates\n    // - - wrt free mem point\n    // - - wrt bytes representation in memory\n    // - - wrt memory addressing in general\n\n    // Usage:\n    // - create type constants\n    // - use `assertType` for runtime type assertions\n    // - - unfortunately we can't do this at compile time yet :(\n    // - recommended: implement modifiers that perform type checking\n    // - - e.g.\n    // - - `uint40 constant MY_TYPE = 3;`\n    // - - ` modifier onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }`\n    // - instantiate a typed view from a bytearray using `ref`\n    // - use `index` to inspect the contents of the view\n    // - use `slice` to create smaller views into the same memory\n    // - - `slice` can increase the offset\n    // - - `slice can decrease the length`\n    // - - must specify the output type of `slice`\n    // - - `slice` will return a null view if you try to overrun\n    // - - make sure to explicitly check for this with `notNull` or `assertType`\n    // - use `equal` for typed comparisons.\n\n    // The null view\n    bytes29 public constant NULL = hex\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\";\n\n    /**\n     * @dev Memory layout for bytes29\n     * [000..005)   type     5 bytes    Type flag for the pointer\n     * [005..017)   loc     12 bytes    Memory address of underlying bytes\n     * [017..029)   len     12 bytes    Length of underlying bytes\n     * [029..032)   empty    3 bytes    Not used\n     */\n    uint256 public constant BITS_TYPE = 40;\n    uint256 public constant BITS_LOC = 96;\n    uint256 public constant BITS_LEN = 96;\n    uint256 public constant BITS_EMPTY = 24;\n\n    // `SHIFT_X` is how much bits to shift for `X` to be in the very bottom bits\n    uint256 public constant SHIFT_LEN = BITS_EMPTY; // 24\n    uint256 public constant SHIFT_LOC = SHIFT_LEN + BITS_LEN; // 24 + 96 = 120\n    uint256 public constant SHIFT_TYPE = SHIFT_LOC + BITS_LOC; // 24 + 96 + 96 = 216\n    // Bitmask for the lowest 96 bits\n    uint256 public constant LOW_96_BITS_MASK = type(uint96).max;\n\n    // For nibble encoding\n    bytes private constant NIBBLE_LOOKUP = \"0123456789abcdef\";\n\n    /**\n     * @notice Returns the encoded hex character that represents the lower 4 bits of the argument.\n     * @param _byte     The byte\n     * @return _char    The encoded hex character\n     */\n    function nibbleHex(uint8 _byte) internal pure returns (uint8 _char) {\n        uint8 _nibble = _byte \u0026 0x0f; // keep bottom 4 bits, zero out top 4 bits\n        _char = uint8(NIBBLE_LOOKUP[_nibble]);\n    }\n\n    /**\n     * @notice      Returns a uint16 containing the hex-encoded byte.\n     * @param _b    The byte\n     * @return      encoded - The hex-encoded byte\n     */\n    function byteHex(uint8 _b) internal pure returns (uint16 encoded) {\n        encoded |= nibbleHex(_b \u003e\u003e 4); // top 4 bits\n        encoded \u003c\u003c= 8;\n        encoded |= nibbleHex(_b); // lower 4 bits\n    }\n\n    /**\n     * @notice      Encodes the uint256 to hex. `first` contains the encoded top 16 bytes.\n     *              `second` contains the encoded lower 16 bytes.\n     *\n     * @param _b    The 32 bytes as uint256\n     * @return      first - The top 16 bytes\n     * @return      second - The bottom 16 bytes\n     */\n    function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) {\n        for (uint8 i = 31; i \u003e 15; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            first |= byteHex(_byte);\n            if (i != 16) {\n                first \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n\n        // abusing underflow here =_=\n        for (uint8 i = 15; i \u003c 255; ) {\n            uint8 _byte = uint8(_b \u003e\u003e (i * 8));\n            second |= byteHex(_byte);\n            if (i != 0) {\n                second \u003c\u003c= 16;\n            }\n            unchecked {\n                i -= 1;\n            }\n        }\n    }\n\n    /**\n     * @notice          Changes the endianness of a uint256.\n     * @dev             https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel\n     * @param _b        The unsigned integer to reverse\n     * @return          v - The reversed value\n     */\n    function reverseUint256(uint256 _b) internal pure returns (uint256 v) {\n        v = _b;\n\n        // swap bytes\n        v =\n            ((v \u003e\u003e 8) \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n            ((v \u0026 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) \u003c\u003c 8);\n        // swap 2-byte long pairs\n        v =\n            ((v \u003e\u003e 16) \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n            ((v \u0026 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) \u003c\u003c 16);\n        // swap 4-byte long pairs\n        v =\n            ((v \u003e\u003e 32) \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n            ((v \u0026 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) \u003c\u003c 32);\n        // swap 8-byte long pairs\n        v =\n            ((v \u003e\u003e 64) \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n            ((v \u0026 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) \u003c\u003c 64);\n        // swap 16-byte long pairs\n        v = (v \u003e\u003e 128) | (v \u003c\u003c 128);\n    }\n\n    /**\n     * @notice      Create a mask with the highest `_len` bits set.\n     * @param _len  The length\n     * @return      mask - The mask\n     */\n    function leftMask(uint8 _len) private pure returns (uint256 mask) {\n        // 0x800...00 binary representation is 100...00\n        // sar stands for \"signed arithmetic shift\": https://en.wikipedia.org/wiki/Arithmetic_shift\n        // sar(N-1, 100...00) = 11...100..00, with exactly N highest bits set to 1\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mask := sar(\n                sub(_len, 1),\n                0x8000000000000000000000000000000000000000000000000000000000000000\n            )\n        }\n    }\n\n    /**\n     * @notice      Return the null view.\n     * @return      bytes29 - The null view\n     */\n    // solhint-disable-next-line ordering\n    function nullView() internal pure returns (bytes29) {\n        return NULL;\n    }\n\n    /**\n     * @notice      Check if the view is null.\n     * @return      bool - True if the view is null\n     */\n    function isNull(bytes29 memView) internal pure returns (bool) {\n        return memView == NULL;\n    }\n\n    /**\n     * @notice      Check if the view is not null.\n     * @return      bool - True if the view is not null\n     */\n    function notNull(bytes29 memView) internal pure returns (bool) {\n        return !isNull(memView);\n    }\n\n    /**\n     * @notice          Check if the view is of a valid type and points to a valid location\n     *                  in memory.\n     * @dev             We perform this check by examining solidity's unallocated memory\n     *                  pointer and ensuring that the view's upper bound is less than that.\n     * @param memView   The view\n     * @return          ret - True if the view is valid\n     */\n    function isValid(bytes29 memView) internal pure returns (bool ret) {\n        if (typeOf(memView) == 0xffffffffff) {\n            return false;\n        }\n        uint256 _end = end(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // View is valid if (\"upper bound\" \u003c= \"unallocated memory pointer\")\n            // Upper bound is exclusive, hence \"\u003c=\"\n            ret := not(gt(_end, mload(0x40)))\n        }\n    }\n\n    /**\n     * @notice          Require that a typed memory view be valid.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @return          bytes29 - The validated view\n     */\n    function assertValid(bytes29 memView) internal pure returns (bytes29) {\n        require(isValid(memView), \"Validity assertion failed\");\n        return memView;\n    }\n\n    /**\n     * @notice          Return true if the memview is of the expected type. Otherwise false.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bool - True if the memview is of the expected type\n     */\n    function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) {\n        return typeOf(memView) == _expected;\n    }\n\n    /**\n     * @notice          Require that a typed memory view has a specific type.\n     * @dev             Returns the view for easy chaining.\n     * @param memView   The view\n     * @param _expected The expected type\n     * @return          bytes29 - The view with validated type\n     */\n    function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) {\n        if (!isType(memView, _expected)) {\n            (, uint256 g) = encodeHex(uint256(typeOf(memView)));\n            (, uint256 e) = encodeHex(uint256(_expected));\n            string memory err = string(\n                abi.encodePacked(\n                    \"Type assertion failed. Got 0x\",\n                    uint80(g),\n                    \". Expected 0x\",\n                    uint80(e)\n                )\n            );\n            revert(err);\n        }\n        return memView;\n    }\n\n    /**\n     * @notice          Return an identical view with a different type.\n     * @param memView   The view\n     * @param _newType  The new type\n     * @return          newView - The new view with the specified type\n     */\n    function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) {\n        // How many bits are the \"type bits\" occupying\n        uint256 _bitsType = BITS_TYPE;\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // shift off the \"type bits\" (shift left, then sift right)\n            newView := or(newView, shr(_bitsType, shl(_bitsType, memView)))\n            // set the new \"type bits\" (shift left, then OR)\n            newView := or(newView, shl(_shiftType, _newType))\n        }\n    }\n\n    /**\n     * @notice          Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Unsafe raw pointer construction. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function unsafeBuildUnchecked(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) private pure returns (bytes29 newView) {\n        uint256 _bitsLoc = BITS_LOC;\n        uint256 _bitsLen = BITS_LEN;\n        uint256 _bitsEmpty = BITS_EMPTY;\n        // Ref memory layout\n        // [000..005) 5 bytes of type\n        // [005..017) 12 bytes of location\n        // [017..029) 12 bytes of length\n        // last 3 bits are blank and dropped in typecast\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // insert `type`, shift to prepare empty bits for `loc`\n            newView := shl(_bitsLoc, or(newView, _type))\n            // insert `loc`, shift to prepare empty bits for `len`\n            newView := shl(_bitsLen, or(newView, _loc))\n            // insert `len`, shift to insert 3 blank lowest bits\n            newView := shl(_bitsEmpty, or(newView, _len))\n        }\n    }\n\n    /**\n     * @notice          Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @dev             Instantiate a new memory view. This should generally not be called\n     *                  directly. Prefer `ref` wherever possible.\n     * @param _type     The type\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @return          newView - The new view with the specified type, location and length\n     */\n    function build(\n        uint256 _type,\n        uint256 _loc,\n        uint256 _len\n    ) internal pure returns (bytes29 newView) {\n        uint256 _end = _loc + _len;\n        // Make sure that a view is not constructed that points to unallocated memory\n        // as this could be indicative of a buffer overflow attack\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            if gt(_end, mload(0x40)) {\n                _end := 0\n            }\n        }\n        if (_end == 0) {\n            return NULL;\n        }\n        newView = unsafeBuildUnchecked(_type, _loc, _len);\n    }\n\n    /**\n     * @notice          Instantiate a memory view from a byte array.\n     * @dev             Note that due to Solidity memory representation, it is not possible to\n     *                  implement a deref, as the `bytes` type stores its len in memory.\n     * @param arr       The byte array\n     * @param newType   The type\n     * @return          bytes29 - The memory view\n     */\n    function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) {\n        uint256 _len = arr.length;\n        // `bytes arr` is stored in memory in the following way\n        // 1. First, uint256 arr.length is stored. That requires 32 bytes (0x20).\n        // 2. Then, the array data is stored.\n        uint256 _loc;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // We add 0x20, so that the view starts exactly where the array data starts\n            _loc := add(arr, 0x20)\n        }\n\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Return the associated type information.\n     * @param memView   The memory view\n     * @return          _type - The type associated with the view\n     */\n    function typeOf(bytes29 memView) internal pure returns (uint40 _type) {\n        // How many bits are the \"type bits\" shifted from the bottom\n        uint256 _shiftType = SHIFT_TYPE;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"type bits\". \"type bits\" are occupying\n            // the highest bits, so all that's left is \"type bits\", OR is not required.\n            _type := shr(_shiftType, memView)\n        }\n    }\n\n    /**\n     * @notice          Optimized type comparison. Checks that the 5-byte type flag is equal.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the 5-byte type flag is equal\n     */\n    function sameType(bytes29 left, bytes29 right) internal pure returns (bool) {\n        // Check that the highest 5 bytes are equal: xor and shift out lower 27 bytes\n        return (left ^ right) \u003e\u003e SHIFT_TYPE == 0;\n    }\n\n    /**\n     * @notice          Return the memory address of the underlying bytes.\n     * @param memView   The view\n     * @return          _loc - The memory address\n     */\n    function loc(bytes29 memView) internal pure returns (uint96 _loc) {\n        // How many bits are the \"loc bits\" shifted from the bottom\n        uint256 _shiftLoc = SHIFT_LOC;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"loc bits\".\n            // Then use the lowest 96 bits to determine `loc` by applying the bit-mask.\n            _loc := and(shr(_shiftLoc, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          The number of memory words this memory view occupies, rounded up.\n     * @param memView   The view\n     * @return          uint256 - The number of memory words\n     */\n    function words(bytes29 memView) internal pure returns (uint256) {\n        // returning ceil(length / 32.0)\n        return (uint256(len(memView)) + 31) / 32;\n    }\n\n    /**\n     * @notice          The in-memory footprint of a fresh copy of the view.\n     * @param memView   The view\n     * @return          uint256 - The in-memory footprint of a fresh copy of the view.\n     */\n    function footprint(bytes29 memView) internal pure returns (uint256) {\n        return words(memView) * 32;\n    }\n\n    /**\n     * @notice          The number of bytes of the view.\n     * @param memView   The view\n     * @return          _len - The length of the view\n     */\n    function len(bytes29 memView) internal pure returns (uint96 _len) {\n        // How many bits are the \"len bits\" shifted from the bottom\n        uint256 _shiftLen = SHIFT_LEN;\n        // Mask for the bottom 96 bits\n        uint256 _uint96Mask = LOW_96_BITS_MASK;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Shift out the bottom bits preceding \"len bits\".\n            // Then use the lowest 96 bits to determine `len` by applying the bit-mask.\n            _len := and(shr(_shiftLen, memView), _uint96Mask)\n        }\n    }\n\n    /**\n     * @notice          Returns the endpoint of `memView`.\n     * @param memView   The view\n     * @return          uint256 - The endpoint of `memView`\n     */\n    function end(bytes29 memView) internal pure returns (uint256) {\n        unchecked {\n            return loc(memView) + len(memView);\n        }\n    }\n\n    /**\n     * @notice          Safe slicing without memory modification.\n     * @param memView   The view\n     * @param _index    The start index\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function slice(\n        bytes29 memView,\n        uint256 _index,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        uint256 _loc = loc(memView);\n\n        // Ensure it doesn't overrun the view\n        if (_loc + _index + _len \u003e end(memView)) {\n            return NULL;\n        }\n\n        _loc = _loc + _index;\n        return build(newType, _loc, _len);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing\n     *                  bytes from `_index` to end(memView).\n     * @param memView   The view\n     * @param _index    The start index\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function sliceFrom(\n        bytes29 memView,\n        uint256 _index,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, _index, len(memView) - _index, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the first `_len` bytes.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function prefix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, 0, _len, newType);\n    }\n\n    /**\n     * @notice          Shortcut to `slice`. Gets a view representing the last `_len` byte.\n     * @param memView   The view\n     * @param _len      The length\n     * @param newType   The new type\n     * @return          bytes29 - The new view\n     */\n    function postfix(\n        bytes29 memView,\n        uint256 _len,\n        uint40 newType\n    ) internal pure returns (bytes29) {\n        return slice(memView, uint256(len(memView)) - _len, _len, newType);\n    }\n\n    /**\n     * @notice          Construct an error message for an indexing overrun.\n     * @param _loc      The memory address\n     * @param _len      The length\n     * @param _index    The index\n     * @param _slice    The slice where the overrun occurred\n     * @return          err - The err\n     */\n    function indexErrOverrun(\n        uint256 _loc,\n        uint256 _len,\n        uint256 _index,\n        uint256 _slice\n    ) internal pure returns (string memory err) {\n        (, uint256 a) = encodeHex(_loc);\n        (, uint256 b) = encodeHex(_len);\n        (, uint256 c) = encodeHex(_index);\n        (, uint256 d) = encodeHex(_slice);\n        err = string(\n            abi.encodePacked(\n                \"TypedMemView/index - Overran the view. Slice is at 0x\",\n                uint48(a),\n                \" with length 0x\",\n                uint48(b),\n                \". Attempted to index at offset 0x\",\n                uint48(c),\n                \" with length 0x\",\n                uint48(d),\n                \".\"\n            )\n        );\n    }\n\n    /**\n     * @notice          Load up to 32 bytes from the view onto the stack.\n     * @dev             Returns a bytes32 with only the `_bytes` highest bytes set.\n     *                  This can be immediately cast to a smaller fixed-length byte array.\n     *                  To automatically cast to an integer, use `indexUint`.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The 32 byte result\n     */\n    function index(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (bytes32 result) {\n        if (_bytes == 0) {\n            return bytes32(0);\n        }\n        if (_index + _bytes \u003e len(memView)) {\n            revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes)));\n        }\n        require(_bytes \u003c= 32, \"Index: more than 32 bytes\");\n\n        uint8 bitLength;\n        unchecked {\n            bitLength = _bytes * 8;\n        }\n        uint256 _loc = loc(memView);\n        // Get a mask with `bitLength` highest bits set\n        uint256 _mask = leftMask(bitLength);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // Load a full word using index offset, and apply mask to ignore non-relevant bytes\n            result := and(mload(add(_loc, _index)), _mask)\n        }\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from the view at `_index`.\n     * @dev             Requires that the view have \u003e= `_bytes` bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        // `index()` returns left-aligned `_bytes`, while integers are right-aligned\n        // Shifting here to right-align with the full 32 bytes word\n        return uint256(index(memView, _index, _bytes)) \u003e\u003e ((32 - _bytes) * 8);\n    }\n\n    /**\n     * @notice          Parse an unsigned integer from LE bytes.\n     * @param memView   The view\n     * @param _index    The index\n     * @param _bytes    The bytes\n     * @return          result - The unsigned integer\n     */\n    function indexLEUint(\n        bytes29 memView,\n        uint256 _index,\n        uint8 _bytes\n    ) internal pure returns (uint256 result) {\n        return reverseUint256(uint256(index(memView, _index, _bytes)));\n    }\n\n    /**\n     * @notice          Parse an address from the view at `_index`.\n     *                  Requires that the view have \u003e= 20 bytes following that index.\n     * @param memView   The view\n     * @param _index    The index\n     * @return          address - The address\n     */\n    function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) {\n        // index 20 bytes as `uint160`, and then cast to `address`\n        return address(uint160(indexUint(memView, _index, 20)));\n    }\n\n    /**\n     * @notice          Return the keccak256 hash of the underlying memory\n     * @param memView   The view\n     * @return          digest - The keccak256 hash of the underlying memory\n     */\n    function keccak(bytes29 memView) internal pure returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            digest := keccak256(_loc, _len)\n        }\n    }\n\n    /**\n     * @notice          Return the sha2 digest of the underlying memory.\n     * @dev             We explicitly deallocate memory afterwards.\n     * @param memView   The view\n     * @return          digest - The sha2 hash of the underlying memory\n     */\n    function sha2(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            digest := mload(ptr)\n        }\n        require(res, \"sha2: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash160 (rmd160(sha2()))\n     * @param memView   The pre-image\n     * @return          digest - the Digest\n     */\n    function hash160(bytes29 memView) internal view returns (bytes20 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            // rmd160 precompile is 0x03\n            res := and(res, staticcall(gas(), 0x03, ptr, 0x20, ptr, 0x20))\n            digest := mload(add(ptr, 0xc)) // return value is 0-prefixed.\n        }\n        require(res, \"hash160: out of gas\");\n    }\n\n    /**\n     * @notice          Implements bitcoin's hash256 (double sha2)\n     * @param memView   A view of the preimage\n     * @return          digest - the Digest\n     */\n    function hash256(bytes29 memView) internal view returns (bytes32 digest) {\n        uint256 _loc = loc(memView);\n        uint256 _len = len(memView);\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // sha2 precompile is 0x02\n            res := staticcall(gas(), 0x02, _loc, _len, ptr, 0x20)\n            res := and(res, staticcall(gas(), 0x02, ptr, 0x20, ptr, 0x20))\n            digest := mload(ptr)\n        }\n        require(res, \"hash256: out of gas\");\n    }\n\n    /**\n     * @notice          Return true if the underlying memory is equal. Else false.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the underlying memory is equal\n     */\n    function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return\n            (loc(left) == loc(right) \u0026\u0026 len(left) == len(right)) || keccak(left) == keccak(right);\n    }\n\n    /**\n     * @notice          Return false if the underlying memory is equal. Else true.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - False if the underlying memory is equal\n     */\n    function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !untypedEqual(left, right);\n    }\n\n    /**\n     * @notice          Compares type equality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are the same\n     */\n    function equal(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return left == right || (typeOf(left) == typeOf(right) \u0026\u0026 keccak(left) == keccak(right));\n    }\n\n    /**\n     * @notice          Compares type inequality.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param left      The first view\n     * @param right     The second view\n     * @return          bool - True if the types are not the same\n     */\n    function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) {\n        return !equal(left, right);\n    }\n\n    /**\n     * @notice          Copy the view to a location, return an unsafe memory reference\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memView   The view\n     * @param _newLoc   The new location\n     * @return          written - the unsafe memory reference\n     */\n    function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) {\n        require(notNull(memView), \"copyTo: Null pointer deref\");\n        require(isValid(memView), \"copyTo: Invalid pointer deref\");\n        uint256 _len = len(memView);\n        uint256 _oldLoc = loc(memView);\n\n        uint256 ptr;\n        bool res;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _newLoc) {\n                revert(0x60, 0x20) // empty revert message\n            }\n\n            // use the identity precompile (0x04) to copy\n            res := staticcall(gas(), 0x04, _oldLoc, _len, _newLoc, _len)\n        }\n        require(res, \"identity: out of gas\");\n\n        written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len);\n    }\n\n    /**\n     * @notice          Copies the referenced memory to a new loc in memory,\n     *                  returning a `bytes` pointing to the new memory.\n     * @dev             Shortcuts if the pointers are identical, otherwise compares type and digest.\n     * @param memView   The view\n     * @return          ret - The view pointing to the new memory\n     */\n    function clone(bytes29 memView) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        uint256 _len = len(memView);\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n            ret := ptr\n        }\n        unchecked {\n            unsafeCopyTo(memView, ptr + 0x20);\n        }\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer\n            mstore(ptr, _len) // write len of new array (in bytes)\n        }\n    }\n\n    /**\n     * @notice          Join the views in memory, return an unsafe reference to the memory.\n     * @dev             Super Dangerous direct memory access.\n     *\n     *                  This reference can be overwritten if anything else modifies memory (!!!).\n     *                  As such it MUST be consumed IMMEDIATELY.\n     *                  This function is private to prevent unsafe usage by callers.\n     * @param memViews  The views\n     * @return          unsafeView - The conjoined view pointing to the new memory\n     */\n    function unsafeJoin(bytes29[] memory memViews, uint256 _location)\n        private\n        view\n        returns (bytes29 unsafeView)\n    {\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            let ptr := mload(0x40)\n            // revert if we're writing in occupied memory\n            if gt(ptr, _location) {\n                revert(0x60, 0x20) // empty revert message\n            }\n        }\n\n        uint256 _offset = 0;\n        for (uint256 i = 0; i \u003c memViews.length; i++) {\n            bytes29 memView = memViews[i];\n            unchecked {\n                unsafeCopyTo(memView, _location + _offset);\n                _offset += len(memView);\n            }\n        }\n        unsafeView = unsafeBuildUnchecked(0, _location, _offset);\n    }\n\n    /**\n     * @notice          Produce the keccak256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The keccak256 digest\n     */\n    function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return keccak(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          Produce the sha256 digest of the concatenated contents of multiple views.\n     * @param memViews  The views\n     * @return          bytes32 - The sha256 digest\n     */\n    function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n        return sha2(unsafeJoin(memViews, ptr));\n    }\n\n    /**\n     * @notice          copies all views, joins them into a new bytearray.\n     * @param memViews  The views\n     * @return          ret - The new byte array\n     */\n    function join(bytes29[] memory memViews) internal view returns (bytes memory ret) {\n        uint256 ptr;\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            ptr := mload(0x40) // load unused memory pointer\n        }\n\n        bytes29 _newView;\n        unchecked {\n            _newView = unsafeJoin(memViews, ptr + 0x20);\n        }\n        uint256 _written = len(_newView);\n        uint256 _footprint = footprint(_newView);\n\n        assembly {\n            // solhint-disable-previous-line no-inline-assembly\n            // store the length\n            mstore(ptr, _written)\n            // new pointer is old + 0x20 + the footprint of the body\n            mstore(0x40, add(add(ptr, _footprint), 0x20))\n            ret := ptr\n        }\n    }\n}\n\nlibrary SynapseTypes {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          0X00: BYTE STRINGS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * 1. RAW_BYTES refers to a generic byte string, that is not supposed to be parsed\n     * by the messaging contracts. RAW_BYTES is set to uint40(0) so that\n     * the \"default zero\" type would represent a generic byte string.\n     * 2. SIGNATURE refers to 65 bytes string that is an off-chain agent signature for some data.\n     * 3. CALL_PAYLOAD refers to the payload, that is supposed to be used for an external call, i.e.\n     * recipient.call(CALL_PAYLOAD). Its length is always (4 + 32 * N) bytes:\n     *      - First 4 bytes represent the function selector.\n     *      - 32 * N bytes represent N function arguments.\n     */\n    // prettier-ignore\n    uint40 internal constant RAW_BYTES                  = 0x00_00_00_00_00;\n    // prettier-ignore\n    uint40 internal constant SIGNATURE                  = 0x00_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant CALL_PAYLOAD               = 0x00_02_00_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X01: ATTESTATION                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant ATTESTATION                = 0x01_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant ATTESTATION_DATA           = 0x01_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X02: REPORT                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant REPORT                     = 0x02_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant REPORT_DATA                = 0x02_01_01_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         0X03: MESSAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant MESSAGE                    = 0x03_01_00_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_HEADER             = 0x03_01_01_00_00;\n    // prettier-ignore\n    uint40 internal constant MESSAGE_TIPS               = 0x03_01_02_00_00;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             0X04: SYSTEM                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // prettier-ignore\n    uint40 internal constant SYSTEM_CALL                = 0x04_00_00_00_00;\n}\n\nlibrary ByteString {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    // @dev non-compact ECDSA signatures are enforced as of OZ 4.7.3\n    uint256 internal constant SIGNATURE_LENGTH = 65;\n\n    /**\n     * @dev Call payload memory layout\n     * [000 .. 004) selector    bytes4  4 bytes\n     *      Optional: N function arguments\n     * [004 .. 036) arg1        bytes32 32 bytes\n     *      ..\n     * [AAA .. END) argN        bytes32 32 bytes\n     */\n    uint256 internal constant SELECTOR_LENGTH = 4;\n    uint256 internal constant OFFSET_SELECTOR = 0;\n    uint256 internal constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a raw bytes payload.\n     */\n    function castToRawBytes(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.RAW_BYTES);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a signature payload.\n     */\n    function castToSignature(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SIGNATURE);\n    }\n\n    /**\n     * @notice Checks that a byte string is a signature\n     */\n    function isSignature(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == SIGNATURE_LENGTH;\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a call payload.\n     */\n    function castToCallPayload(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.CALL_PAYLOAD);\n    }\n\n    /**\n     * @notice Checks that a byte string is a call payload, i.e.\n     * a function selector, followed by arbitrary amount of arguments.\n     */\n    function isCallPayload(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Call payload should at least have a function selector\n        if (length \u003c SELECTOR_LENGTH) return false;\n        // The remainder of the payload should be exactly N words (N \u003e= 0), i.e.\n        // (length - SELECTOR_LENGTH) % 32 == 0\n        // We're using logical AND here to speed it up a bit\n        return (length - SELECTOR_LENGTH) \u0026 31 == 0;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         CALL PAYLOAD SLICING                         ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns amount of memory words (32 byte chunks) the function arguments\n     * occupy in the call payload.\n     * @dev This might differ from amount of arguments supplied, if any of the arguments\n     * occupies more than one memory slot. It is true, however, that argument part of the payload\n     * occupies exactly N words, even for dynamic types like `bytes`\n     */\n    function argumentWords(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (uint256)\n    {\n        // Equivalent of (length - SELECTOR_LENGTH) / 32\n        return (_view.len() - SELECTOR_LENGTH) \u003e\u003e 5;\n    }\n\n    /// @notice Returns selector for the provided call payload.\n    function callSelector(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return\n            _view.slice({\n                _index: OFFSET_SELECTOR,\n                _len: SELECTOR_LENGTH,\n                newType: SynapseTypes.RAW_BYTES\n            });\n    }\n\n    /// @notice Returns abi encoded arguments for the provided call payload.\n    function argumentsPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.CALL_PAYLOAD)\n        returns (bytes29)\n    {\n        return _view.sliceFrom({ _index: OFFSET_ARGUMENTS, newType: SynapseTypes.RAW_BYTES });\n    }\n}\n\nlibrary Attestation {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev AttestationData memory layout\n     * [000 .. 004): origin         uint32   4 bytes\n     * [004 .. 008): destination    uint32   4 bytes\n     * [008 .. 012): nonce          uint32   4 bytes\n     * [012 .. 044): root           bytes32 32 bytes\n     *\n     *      Attestation memory layout\n     * [000 .. 044): attData        bytes   44 bytes (see above)\n     * [044 .. 109): signature      bytes   65 bytes (65 bytes)\n     */\n\n    uint256 internal constant OFFSET_ORIGIN = 0;\n    uint256 internal constant OFFSET_DESTINATION = 4;\n    uint256 internal constant OFFSET_NONCE = 8;\n    uint256 internal constant OFFSET_ROOT = 12;\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant OFFSET_SIGNATURE = ATTESTATION_DATA_LENGTH;\n    uint256 internal constant ATTESTATION_LENGTH = ATTESTATION_DATA_LENGTH + 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyAttestation(bytes29 _view) {\n        _view.assertType(SynapseTypes.ATTESTATION);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for an attestation payload.\n     */\n    function castToAttestation(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.ATTESTATION);\n    }\n\n    /**\n     * @notice Returns a formatted Attestation payload with provided fields\n     * @param _data         Attestation Data (see above)\n     * @param _signature    Notary's signature on `_data`\n     * @return Formatted attestation\n     **/\n    function formatAttestation(bytes memory _data, bytes memory _signature)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return abi.encodePacked(_data, _signature);\n    }\n\n    /**\n     * @notice Returns a formatted AttestationData payload with provided fields\n     * @param _origin       Domain of Origin's chain\n     * @param _destination  Domain of Destination's chain\n     * @param _root         New merkle root\n     * @param _nonce        Nonce of the merkle root\n     * @return Formatted attestation data\n     **/\n    function formatAttestationData(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(_origin, _destination, _nonce, _root);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Attestation payload.\n     */\n    function isAttestation(bytes29 _view) internal pure returns (bool) {\n        return _view.len() == ATTESTATION_LENGTH;\n    }\n\n    /**\n     * @notice Combines origin and destination domains into `attestationDomains`,\n     * a unique ID for every (origin, destination) pair. Could be used to identify\n     * Merkle trees on Origin, or Mirrors on Destination.\n     */\n    function attestationDomains(uint32 _origin, uint32 _destination)\n        internal\n        pure\n        returns (uint64)\n    {\n        return (uint64(_origin) \u003c\u003c 32) | _destination;\n    }\n\n    /**\n     * @notice Combines origin, destination domains and message nonce into `attestationKey`,\n     * a unique key for every (origin, destination, nonce) tuple. Could be used to identify\n     * any dispatched message.\n     */\n    function attestationKey(\n        uint32 _origin,\n        uint32 _destination,\n        uint32 _nonce\n    ) internal pure returns (uint96) {\n        return (uint96(_origin) \u003c\u003c 64) | (uint96(_destination) \u003c\u003c 32) | _nonce;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         ATTESTATION SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns domain of chain where the Origin contract is deployed\n     */\n    function attestedOrigin(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns domain of chain where the Destination contract is deployed\n     */\n    function attestedDestination(bytes29 _view)\n        internal\n        pure\n        onlyAttestation(_view)\n        returns (uint32)\n    {\n        return uint32(_view.indexUint({ _index: OFFSET_DESTINATION, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns nonce of Origin contract at the time, when `root` was the Merkle root.\n     */\n    function attestedNonce(bytes29 _view) internal pure onlyAttestation(_view) returns (uint32) {\n        return uint32(_view.indexUint({ _index: OFFSET_NONCE, _bytes: 4 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination). See `attestationDomains()`.\n     */\n    function attestedDomains(bytes29 _view) internal pure onlyAttestation(_view) returns (uint64) {\n        return uint64(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 8 }));\n    }\n\n    /**\n     * @notice Returns a combined field for (origin, destination, nonce). See `attestationKey()`.\n     */\n    function attestedKey(bytes29 _view) internal pure onlyAttestation(_view) returns (uint96) {\n        return uint96(_view.indexUint({ _index: OFFSET_ORIGIN, _bytes: 12 }));\n    }\n\n    /**\n     * @notice Returns a historical Merkle root from the Origin contract\n     */\n    function attestedRoot(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes32) {\n        return _view.index({ _index: OFFSET_ROOT, _bytes: 32 });\n    }\n\n    /**\n     * @notice Returns Attestation's Data, that is going to be signed by the Notary\n     */\n    function attestationData(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ORIGIN,\n                _len: ATTESTATION_DATA_LENGTH,\n                newType: SynapseTypes.ATTESTATION_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Notary's signature on AttestationData\n     */\n    function notarySignature(bytes29 _view) internal pure onlyAttestation(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_SIGNATURE,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n}\n\nlibrary Report {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev More flag values could be added in the future,\n     *      e.g. flag indicating \"type\" of fraud.\n     *      Going forward, Flag.Valid is guaranteed to be\n     *      the only Flag specifying a valid attestation.\n     *\n     *      Flag.Valid indicates a reported valid Attestation.\n     *      Flag.Fraud indicates a reported fraud Attestation.\n     */\n    enum Flag {\n        Valid,\n        Fraud\n    }\n\n    /**\n     * @dev ReportData memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     *\n     * guardSig is Guard's signature on ReportData\n     *\n     *      Report memory layout\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 110): attestation    bytes   109 bytes (44 + 65 bytes)\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     *      Unpack attestation field (see Attestation.sol)\n     * [000 .. 001): flag           uint8    1 bytes\n     * [001 .. 045): attData        bytes   44 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 175): guardSig       bytes   65 bytes\n     *\n     * notarySig is Notary's signature on AttestationData\n     *\n     * flag + attData = reportData (see above), so\n     *\n     *      Report memory layout (sliced alternatively)\n     * [000 .. 045): reportData     bytes   45 bytes\n     * [045 .. 110): notarySig      bytes   65 bytes\n     * [110 .. 171): guardSig       bytes   61 bytes\n     */\n\n    uint256 internal constant OFFSET_FLAG = 0;\n    uint256 internal constant OFFSET_ATTESTATION = 1;\n\n    uint256 internal constant ATTESTATION_DATA_LENGTH = 44;\n    uint256 internal constant REPORT_DATA_LENGTH = 1 + ATTESTATION_DATA_LENGTH;\n    uint256 internal constant REPORT_LENGTH = REPORT_DATA_LENGTH + 2 * 65;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyReport(bytes29 _view) {\n        _view.assertType(SynapseTypes.REPORT);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                       FORMATTERS: REPORT DATA                        ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns formatted report data with provided fields\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatReportData(Flag _flag, bytes memory _attestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        // Extract attestation data from payload\n        bytes memory attestationData = _attestation.castToAttestation().attestationData().clone();\n        // Construct report data\n        return abi.encodePacked(uint8(_flag), attestationData);\n    }\n\n    /**\n     * @notice Returns formatted report data on valid attestation with provided fields\n     * @param _validAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatValidReportData(bytes memory _validAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Valid, _validAttestation);\n    }\n\n    /**\n     * @notice Returns formatted report data on fraud attestation with provided fields\n     * @param _fraudAttestation  Formatted attestation (see Attestation.sol)\n     * @return Formatted report data\n     **/\n    function formatFraudReportData(bytes memory _fraudAttestation)\n        internal\n        view\n        returns (bytes memory)\n    {\n        return formatReportData(Flag.Fraud, _fraudAttestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          FORMATTERS: REPORT                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a report payload.\n     */\n    function castToReport(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.REPORT);\n    }\n\n    /**\n     * @notice Returns formatted report payload with provided fields.\n     * @param _flag         Flag indicating whether attestation is fraudulent\n     * @param _attestation  Formatted attestation (see Attestation.sol)\n     * @param _guardSig     Guard signature on reportData (see formatReportData below)\n     * @return Formatted report\n     **/\n    function formatReport(\n        Flag _flag,\n        bytes memory _attestation,\n        bytes memory _guardSig\n    ) internal pure returns (bytes memory) {\n        return abi.encodePacked(uint8(_flag), _attestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a valid attestation with provided fields.\n     * @param _validAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatValidReport(bytes memory _validAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Valid, _validAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Returns formatted report payload on a fraud attestation with provided fields.\n     * @param _fraudAttestation Formatted attestation (see Attestation.sol)\n     * @param _guardSig         Guard signature on reportData (see ReportData section above)\n     * @return Formatted report\n     **/\n    function formatFraudReport(bytes memory _fraudAttestation, bytes memory _guardSig)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return formatReport(Flag.Fraud, _fraudAttestation, _guardSig);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Report payload.\n     */\n    function isReport(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Report should be the correct length\n        if (length != REPORT_LENGTH) return false;\n        // Flag needs to match an existing enum value\n        if (_flagIntValue(_view) \u003e uint8(type(Flag).max)) return false;\n        // Attestation needs to be formatted as well\n        return reportedAttestation(_view).isAttestation();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            REPORT SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether Report's Flag is Fraud (indicating fraudulent attestation).\n     */\n    function reportedFraud(bytes29 _view) internal pure onlyReport(_view) returns (bool) {\n        return _flagIntValue(_view) != uint8(Flag.Valid);\n    }\n\n    /**\n     * @notice Returns Report's Attestation (which is supposed to be signed by the Notary already).\n     */\n    function reportedAttestation(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        return\n            _view.slice({\n                _index: OFFSET_ATTESTATION,\n                _len: Attestation.ATTESTATION_LENGTH,\n                newType: SynapseTypes.ATTESTATION\n            });\n    }\n\n    /**\n     * @notice Returns Report's Data, that is going to be signed by the Guard.\n     */\n    function reportData(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        // reportData starts from Flag\n        return\n            _view.slice({\n                _index: OFFSET_FLAG,\n                _len: REPORT_DATA_LENGTH,\n                newType: SynapseTypes.REPORT_DATA\n            });\n    }\n\n    /**\n     * @notice Returns Guard's signature on ReportData.\n     */\n    function guardSignature(bytes29 _view) internal pure onlyReport(_view) returns (bytes29) {\n        uint256 offsetSignature = OFFSET_ATTESTATION + Attestation.ATTESTATION_LENGTH;\n        return\n            _view.slice({\n                _index: offsetSignature,\n                _len: ByteString.SIGNATURE_LENGTH,\n                newType: SynapseTypes.SIGNATURE\n            });\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Returns int value of Report flag.\n     *      Needed to prevent overflow when casting to Flag.\n     */\n    function _flagIntValue(bytes29 _view) private pure returns (uint8 flagIntValue) {\n        flagIntValue = uint8(_view.indexUint({ _index: OFFSET_FLAG, _bytes: 1 }));\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp \u003e\u003e= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n            value \u003e\u003e= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs \u0026 bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) \u003e\u003e 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 \u0026\u0026 v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n\nlibrary Auth {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @notice Recovers signer from data and signature.\n     * @param _data         Data that was signed\n     * @param _signature    `_data` signed by `signer`\n     * @return signer       Address that signed the data\n     */\n    function recoverSigner(bytes29 _data, bytes memory _signature)\n        internal\n        pure\n        returns (address signer)\n    {\n        bytes32 digest = _data.keccak();\n        digest = ECDSA.toEthSignedMessageHash(digest);\n        signer = ECDSA.recover(digest, _signature);\n    }\n}\n\nabstract contract NotaryRegistryEvents {\n    /*\n     * @notice Emitted when a new Notary is added.\n     * @param domain    Domain where a Notary was added\n     * @param notary    Address of the added notary\n     */\n    event NotaryAdded(uint32 indexed domain, address notary);\n\n    /**\n     * @notice Emitted when a new Notary is removed.\n     * @param domain    Domain where a Notary was removed\n     * @param notary    Address of the removed notary\n     */\n    event NotaryRemoved(uint32 indexed domain, address notary);\n}\n\nabstract contract AbstractNotaryRegistry is NotaryRegistryEvents {\n    using Attestation for bytes;\n    using Attestation for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Notary to Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is added\n     * @param _notary   New Notary to add\n     * @return TRUE if a notary was added\n     */\n    function _addNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Notary from Registry.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain where Notary is removed\n     * @param _notary   Notary to remove\n     * @return TRUE if a notary was removed\n     */\n    function _removeNotary(uint32 _origin, address _notary) internal virtual returns (bool);\n\n    // solhint-disable no-empty-blocks\n    /**\n     * @notice Hook that is called just before a Notary is added for specified domain.\n     */\n    function _beforeNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is added for specified domain.\n     */\n    function _afterNotaryAdded(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called just before a Notary is removed from specified domain.\n     */\n    function _beforeNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    /**\n     * @notice Hook that is called right after a Notary is removed from specified domain.\n     */\n    function _afterNotaryRemoved(uint32 _domain, address _notary) internal virtual {}\n\n    // solhint-enable no-empty-blocks\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_attestation` is a formatted Attestation payload\n     *          - `_attestation` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _attestation  Attestation of Origin merkle root\n     * @return _notary      Notary that signed the Attestation\n     * @return _view        Memory view on attestation\n     */\n    function _checkNotaryAuth(bytes memory _attestation)\n        internal\n        view\n        returns (address _notary, bytes29 _view)\n    {\n        _view = _attestation.castToAttestation();\n        _notary = _checkNotaryAuth(_view);\n    }\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_view` is a memory view on a formatted Attestation payload\n     *          - `_view` contains a signature\n     *          - such signature belongs to an authorized Notary\n     * @param _view     Memory view on Attestation of Origin merkle root\n     * @return _notary  Notary that signed the Attestation\n     */\n    function _checkNotaryAuth(bytes29 _view) internal view returns (address _notary) {\n        require(_view.isAttestation(), \"Not an attestation\");\n        _notary = Auth.recoverSigner(_view.attestationData(), _view.notarySignature().clone());\n        require(_isNotary(_view.attestedOrigin(), _notary), \"Signer is not a notary\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Notary.\n     * @dev Child contracts should implement this depending on how Notaries are stored.\n     * @param _origin   Origin domain to check\n     * @param _account  Address to check for being a Notary\n     * @return TRUE if the account is an authorized Notary.\n     */\n    function _isNotary(uint32 _origin, address _account) internal view virtual returns (bool);\n}\n\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 =\u003e uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n\nabstract contract DomainNotaryRegistry is AbstractNotaryRegistry, DomainContext {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active notaries for the tracked chain\n    EnumerableSet.AddressSet internal notaries;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that there is at least one active Notary.\n     */\n    modifier haveActiveNotary() {\n        require(notariesAmount() != 0, \"!notaries\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Notaries.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allNotaries() external view returns (address[] memory) {\n        return notaries.values();\n    }\n\n    /**\n     * @notice Returns i-th Notary. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getNotary(uint256 _index) public view returns (address) {\n        return notaries.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active notaries. O(1)\n     */\n    function notariesAmount() public view returns (uint256) {\n        return notaries.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _addNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _addNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to add a new notary, emits an event only if notary was added.\n     */\n    function _addNotary(address _notary) internal returns (bool notaryAdded) {\n        // Notary is added only if they were not previously active\n        notaryAdded = !_isNotary(_notary);\n        if (notaryAdded) {\n            uint32 local = _localDomain();\n            // Trigger \"before added\" hook\n            _beforeNotaryAdded(local, _notary);\n            // Add Notary to local domain\n            notaries.add(_notary);\n            emit NotaryAdded(local, _notary);\n            // Trigger \"after added\" hook\n            _afterNotaryAdded(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _removeNotary(uint32 _domain, address _notary)\n        internal\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _removeNotary(_notary);\n    }\n\n    /**\n     * @notice Tries to remove a notary, emits an event only if notary was removed.\n     */\n    function _removeNotary(address _notary) internal returns (bool notaryRemoved) {\n        // Notary is removed only if they were previously active\n        notaryRemoved = _isNotary(_notary);\n        if (notaryRemoved) {\n            uint32 local = _localDomain();\n            // Trigger \"before removed\" hook\n            _beforeNotaryRemoved(local, _notary);\n            // Remove Notary from local domain\n            notaries.remove(_notary);\n            emit NotaryRemoved(local, _notary);\n            // Trigger \"after removed\" hook\n            _afterNotaryRemoved(local, _notary);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     * @dev Reverts if domain doesn't match the tracked domain.\n     */\n    function _isNotary(uint32 _domain, address _account)\n        internal\n        view\n        override\n        onlyLocalDomain(_domain)\n        returns (bool)\n    {\n        return _isNotary(_account);\n    }\n\n    /**\n     * @notice Returns whether given address is a notary for the tracked domain.\n     */\n    function _isNotary(address _account) internal view returns (bool) {\n        return notaries.contains(_account);\n    }\n}\n\nabstract contract GuardRegistryEvents {\n    /**\n     * @notice Emitted when a new Guard is added.\n     * @param guard    Address of the added guard\n     */\n    event GuardAdded(address guard);\n\n    /**\n     * @notice Emitted when a Guard is removed.\n     * @param guard    Address of the removed guard\n     */\n    event GuardRemoved(address guard);\n}\n\nabstract contract AbstractGuardRegistry is GuardRegistryEvents {\n    using Report for bytes;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Adds a new Guard to Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    New Guard to add\n     * @return TRUE if a guard was added\n     */\n    function _addGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice Removes a Guard from Registry.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _guard    Guard to remove\n     * @return TRUE if a guard was removed\n     */\n    function _removeGuard(address _guard) internal virtual returns (bool);\n\n    /**\n     * @notice  Checks all following statements are true:\n     *          - `_report` is a formatted Report payload\n     *          - `_report` contains a signature\n     *          - such signature belongs to an authorized Guard\n     * @param _report   Report on a Attestation of Origin merkle root\n     * @return _guard   Notary that signed the Attestation\n     * @return _view    Memory view on report\n     */\n    function _checkGuardAuth(bytes memory _report)\n        internal\n        view\n        returns (address _guard, bytes29 _view)\n    {\n        _view = _report.castToReport();\n        require(_view.isReport(), \"Not a report\");\n        _guard = Auth.recoverSigner(_view.reportData(), _view.guardSignature().clone());\n        require(_isGuard(_guard), \"Signer is not a guard\");\n    }\n\n    /**\n     * @notice Checks whether a given account in an authorized Guard.\n     * @dev Child contracts should implement this depending on how Guards are stored.\n     * @param _account  Address to check for being a Guard\n     * @return TRUE if the account is an authorized Guard.\n     */\n    function _isGuard(address _account) internal view virtual returns (bool);\n}\n\ncontract GuardRegistry is AbstractGuardRegistry {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // All active guards\n    EnumerableSet.AddressSet internal guards;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns addresses of all Guards.\n     * @dev This copies storage into memory, so can consume a lof of gas, if\n     * amount of notaries is large (see EnumerableSet.values())\n     */\n    function allGuards() external view returns (address[] memory) {\n        return guards.values();\n    }\n\n    /**\n     * @notice Returns i-th Guard. O(1)\n     * @dev Will revert if index is out of range\n     */\n    function getGuard(uint256 _index) external view returns (address) {\n        return guards.at(_index);\n    }\n\n    /**\n     * @notice Returns amount of active guards. O(1)\n     */\n    function guardsAmount() external view returns (uint256) {\n        return guards.length();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Tries to add a new guard, emits an event only if guard was added.\n     */\n    function _addGuard(address _guard) internal override returns (bool guardAdded) {\n        guardAdded = guards.add(_guard);\n        if (guardAdded) {\n            emit GuardAdded(_guard);\n        }\n    }\n\n    /**\n     * @notice Tries to remove a guard, emits an event only if guard was removed.\n     */\n    function _removeGuard(address _guard) internal override returns (bool guardRemoved) {\n        guardRemoved = guards.remove(_guard);\n        if (guardRemoved) {\n            emit GuardRemoved(_guard);\n        }\n    }\n\n    /**\n     * @notice Returns whether given address is a guard.\n     */\n    function _isGuard(address _account) internal view override returns (bool) {\n        return guards.contains(_account);\n    }\n}\n\nabstract contract OriginHubEvents {\n    /**\n     * @notice Emitted when a correct report on a fraud attestation is submitted.\n     * @param guard     Guard who signed the fraud report\n     * @param report    Report data and signature\n     */\n    event CorrectFraudReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an incorrect report is submitted.\n     * @param guard     Guard who signed the incorrect report\n     * @param report    Report data and signature\n     */\n    event IncorrectReport(address indexed guard, bytes report);\n\n    /**\n     * @notice Emitted when proof of an fraud attestation is submitted.\n     * @param notary        Notary who signed fraud attestation\n     * @param attestation   Attestation data and signature\n     */\n    event FraudAttestation(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHubEvents {\n    /**\n     * @notice Emitted when an attestation is submitted to AttestationHub.\n     * @param notary        Notary who signed the attestation\n     * @param attestation   Raw payload with attestation data and notary signature\n     */\n    event AttestationAccepted(address indexed notary, bytes attestation);\n}\n\nabstract contract AttestationHub is AttestationHubEvents, AbstractNotaryRegistry {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed attestation for handling.\n     * @dev Reverts if either of this is true:\n     *      - Attestation payload is not properly formatted.\n     *      - Attestation signer is not a Notary.\n     * @param _attestation  Payload with Attestation data and signature (see Attestation.sol)\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function submitAttestation(bytes memory _attestation) external returns (bool) {\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted.\n        (address _notary, bytes29 _attestationView) = _checkNotaryAuth(_attestation);\n        // Pass _attestationView as the existing bytes29 pointer to attestation payload\n        // Pass _attestation to avoid extra memory copy when emitting attestation payload\n        return _handleAttestation(_notary, _attestationView, _attestation);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Child contract should implement logic for handling the Attestation.\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return TRUE if Attestation was handled correctly.\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal virtual returns (bool);\n}\n\nabstract contract ReportHub is AbstractGuardRegistry, AbstractNotaryRegistry {\n    using Report for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Called by the external agent. Submits the signed report for handling.\n     * @dev Reverts if either of this is true:\n     *      - Report payload is not properly formatted.\n     *      - Report signer is not a Guard.\n     *      - Reported notary is not a Notary.\n     * @param _report\tPayload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function submitReport(bytes memory _report) external returns (bool) {\n        // Check if real Guard \u0026 signature.\n        // This also checks if Report payload is properly formatted.\n        (address _guard, bytes29 _reportView) = _checkGuardAuth(_report);\n        bytes29 _attestationView = _reportView.reportedAttestation();\n        // Check if real Notary \u0026 signature.\n        // This also checks if Attestation payload is properly formatted,\n        // though it's already been checked in _checkGuardAuth(_report) [see Report.sol].\n        address _notary = _checkNotaryAuth(_attestationView);\n        // Pass _reportView as the existing bytes29 pointer to report payload.\n        // Pass _report to avoid extra memory copy when emitting report payload.\n        return _handleReport(_guard, _notary, _attestationView, _reportView, _report);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          VIRTUAL FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Implement logic for handling the Report in the child contracts.\n     * Note: Report can have either Valid or Fraud flag, make sure to check that.\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _reportView       Memory view over Report for convenience\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was handled correctly.\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal virtual returns (bool);\n}\n\nlibrary MerkleLib {\n    uint256 internal constant TREE_DEPTH = 32;\n    uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;\n\n    /**\n     * @notice Struct representing incremental merkle tree. Contains the current branch,\n     * while the number of inserted leaves are stored externally.\n     **/\n    // solhint-disable-next-line ordering\n    struct Tree {\n        bytes32[TREE_DEPTH] branch;\n    }\n\n    /**\n     * @notice Inserts `_node` into merkle tree\n     * @dev Reverts if tree is full\n     * @param _newCount Amount of inserted leaves in the tree after the insertion (i.e. current + 1)\n     * @param _node     Element to insert into tree\n     **/\n    function insert(\n        Tree storage _tree,\n        uint256 _newCount,\n        bytes32 _node\n    ) internal {\n        require(_newCount \u003c= MAX_LEAVES, \"merkle tree full\");\n        // No need to increase _newCount here,\n        // as it is already the amount of leaves after the insertion.\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            if ((_newCount \u0026 1) == 1) {\n                _tree.branch[i] = _node;\n                return;\n            }\n            _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n            _newCount \u003e\u003e= 1;\n            unchecked {\n                ++i;\n            }\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root given array of zero\n     * hashes\n     * @param _count    Current amount of inserted leaves in the tree\n     * @param _zeroes   Array of zero hashes\n     * @return _current Calculated root of `_tree`\n     **/\n    function rootWithCtx(\n        Tree storage _tree,\n        uint256 _count,\n        bytes32[TREE_DEPTH] memory _zeroes\n    ) internal view returns (bytes32 _current) {\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_count \u003e\u003e i) \u0026 0x01;\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_tree.branch[i], _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates and returns`_tree`'s current root\n     * @param _count    Current amount of inserted leaves in the tree\n     * @return Calculated root of `_tree`\n     **/\n    function root(Tree storage _tree, uint256 _count) internal view returns (bytes32) {\n        return rootWithCtx(_tree, _count, zeroHashes());\n    }\n\n    /// @notice Returns array of TREE_DEPTH zero hashes\n    /// @return _zeroes Array of TREE_DEPTH zero hashes\n    function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n        _zeroes[0] = Z_0;\n        _zeroes[1] = Z_1;\n        _zeroes[2] = Z_2;\n        _zeroes[3] = Z_3;\n        _zeroes[4] = Z_4;\n        _zeroes[5] = Z_5;\n        _zeroes[6] = Z_6;\n        _zeroes[7] = Z_7;\n        _zeroes[8] = Z_8;\n        _zeroes[9] = Z_9;\n        _zeroes[10] = Z_10;\n        _zeroes[11] = Z_11;\n        _zeroes[12] = Z_12;\n        _zeroes[13] = Z_13;\n        _zeroes[14] = Z_14;\n        _zeroes[15] = Z_15;\n        _zeroes[16] = Z_16;\n        _zeroes[17] = Z_17;\n        _zeroes[18] = Z_18;\n        _zeroes[19] = Z_19;\n        _zeroes[20] = Z_20;\n        _zeroes[21] = Z_21;\n        _zeroes[22] = Z_22;\n        _zeroes[23] = Z_23;\n        _zeroes[24] = Z_24;\n        _zeroes[25] = Z_25;\n        _zeroes[26] = Z_26;\n        _zeroes[27] = Z_27;\n        _zeroes[28] = Z_28;\n        _zeroes[29] = Z_29;\n        _zeroes[30] = Z_30;\n        _zeroes[31] = Z_31;\n    }\n\n    /**\n     * @notice Calculates and returns the merkle root for the given leaf\n     * `_item`, a merkle branch, and the index of `_item` in the tree.\n     * @param _item Merkle leaf\n     * @param _branch Merkle proof\n     * @param _index Index of `_item` in tree\n     * @return _current Calculated merkle root\n     **/\n    function branchRoot(\n        bytes32 _item,\n        bytes32[TREE_DEPTH] memory _branch,\n        uint256 _index\n    ) internal pure returns (bytes32 _current) {\n        _current = _item;\n\n        for (uint256 i = 0; i \u003c TREE_DEPTH; ) {\n            uint256 _ithBit = (_index \u003e\u003e i) \u0026 0x01;\n            bytes32 _next = _branch[i];\n            if (_ithBit == 1) {\n                _current = keccak256(abi.encodePacked(_next, _current));\n            } else {\n                _current = keccak256(abi.encodePacked(_current, _next));\n            }\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // keccak256 zero hashes\n    bytes32 internal constant Z_0 =\n        hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n    bytes32 internal constant Z_1 =\n        hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n    bytes32 internal constant Z_2 =\n        hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n    bytes32 internal constant Z_3 =\n        hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n    bytes32 internal constant Z_4 =\n        hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n    bytes32 internal constant Z_5 =\n        hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n    bytes32 internal constant Z_6 =\n        hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n    bytes32 internal constant Z_7 =\n        hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n    bytes32 internal constant Z_8 =\n        hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n    bytes32 internal constant Z_9 =\n        hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n    bytes32 internal constant Z_10 =\n        hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n    bytes32 internal constant Z_11 =\n        hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n    bytes32 internal constant Z_12 =\n        hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n    bytes32 internal constant Z_13 =\n        hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n    bytes32 internal constant Z_14 =\n        hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n    bytes32 internal constant Z_15 =\n        hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n    bytes32 internal constant Z_16 =\n        hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n    bytes32 internal constant Z_17 =\n        hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n    bytes32 internal constant Z_18 =\n        hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n    bytes32 internal constant Z_19 =\n        hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n    bytes32 internal constant Z_20 =\n        hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n    bytes32 internal constant Z_21 =\n        hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n    bytes32 internal constant Z_22 =\n        hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n    bytes32 internal constant Z_23 =\n        hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n    bytes32 internal constant Z_24 =\n        hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n    bytes32 internal constant Z_25 =\n        hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n    bytes32 internal constant Z_26 =\n        hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n    bytes32 internal constant Z_27 =\n        hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n    bytes32 internal constant Z_28 =\n        hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n    bytes32 internal constant Z_29 =\n        hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n    bytes32 internal constant Z_30 =\n        hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n    bytes32 internal constant Z_31 =\n        hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n\nabstract contract OriginHub is\n    OriginHubEvents,\n    AttestationHub,\n    ReportHub,\n    DomainNotaryRegistry,\n    GuardRegistry\n{\n    using Attestation for bytes29;\n    using Report for bytes29;\n    using TypedMemView for bytes29;\n\n    using MerkleLib for MerkleLib.Tree;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // [destination domain] =\u003e [Merkle Tree containing all hashes of sent messages to that domain]\n    mapping(uint32 =\u003e MerkleLib.Tree) internal trees;\n    // [destination domain] =\u003e [Merkle tree roots after inserting a sent message to that domain]\n    mapping(uint32 =\u003e bytes32[]) internal historicalRoots;\n    // [destination domain] =\u003e [block numbers for each nonce written so far]\n    mapping(uint32 =\u003e uint256[]) internal historicalNonceBlockNumbers;\n\n    // gap for upgrade safety\n    uint256[48] private __GAP; // solhint-disable-line var-name-mixedcase\n\n    // Merkle root for an empty merkle tree.\n    bytes32 internal constant EMPTY_TREE_ROOT =\n        hex\"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\";\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                                VIEWS                                 ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Suggest attestation for the off-chain actors to sign for a specific destination.\n     * Note: signing the suggested attestation will will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @dev If no messages have been sent, following values are returned:\n     * - nonce = 0\n     * - root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757\n     * Which is the merkle root for an empty merkle tree.\n     * @return latestNonce Current nonce\n     * @return latestRoot  Current merkle root\n     */\n    function suggestAttestation(uint32 _destination)\n        external\n        view\n        returns (uint32 latestNonce, bytes32 latestRoot)\n    {\n        latestNonce = nonce(_destination);\n        uint256 rootDispatchBlockNumber;\n        uint256 currentBlockNumer;\n        (latestRoot, rootDispatchBlockNumber, currentBlockNumer) = getHistoricalRoot(\n            _destination,\n            latestNonce\n        );\n    }\n\n    // TODO: add suggestAttestations() once OriginHub inherits from GlobalNotaryRegistry\n\n    /**\n     * @notice Returns a historical merkle root for the given destination.\n     * Note: signing the attestation with the given historical root will never lead\n     * to slashing of the actor, assuming they have confirmed that the block, where the merkle root\n     * was updated, is not subject to reorganization (which is different for every observed chain).\n     * @param _destination  Destination domain\n     * @param _nonce        Historical nonce\n     * @return Root for destination's merkle tree right after message to `_destination`\n     * with `nonce = _nonce` was dispatched.\n     */\n    function getHistoricalRoot(uint32 _destination, uint32 _nonce)\n        public\n        view\n        returns (\n            bytes32,\n            uint256,\n            uint256\n        )\n    {\n        // Check if destination is known\n        if (historicalRoots[_destination].length \u003e 0) {\n            // Check if nonce exists\n            require(_nonce \u003c historicalRoots[_destination].length, \"!nonce: existing destination\");\n            return (\n                historicalRoots[_destination][_nonce],\n                historicalNonceBlockNumbers[_destination][_nonce],\n                block.number\n            );\n        } else {\n            // If destination is unknown, we have the root of an empty merkle tree\n            require(_nonce == 0, \"!nonce: unknown destination\");\n            return (EMPTY_TREE_ROOT, uint256(0), block.number);\n        }\n    }\n\n    /**\n     * @notice Returns nonce of the last inserted Merkle root for the given destination,\n     * which is also the number of inserted leaves in the destination merkle tree (current index).\n     */\n    function nonce(uint32 _destination) public view returns (uint32 latestNonce) {\n        latestNonce = uint32(_getTreeCount(_destination));\n    }\n\n    /**\n     * @notice Calculates and returns tree's current root for the given destination.\n     */\n    function root(uint32 _destination) public view returns (bytes32) {\n        return trees[_destination].root(_getTreeCount(_destination));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Checks if a submitted Attestation is a valid Attestation.\n     * Attestation Flag can be either \"Fraud\" or \"Valid\".\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Notary signature and role have been checked in AttestationHub,\n     * hence `_notary` is an active Notary at this point.\n     *\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation for convenience\n     * @param _attestation      Payload with Attestation data and signature\n     * @return isValid          TRUE if Attestation was valid (implying Notary was not slashed).\n     */\n    function _handleAttestation(\n        address _notary,\n        bytes29 _attestationView,\n        bytes memory _attestation\n    ) internal override returns (bool isValid) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        isValid = _isValidAttestation(attestedDestination, attestedNonce, attestedRoot);\n        if (!isValid) {\n            emit FraudAttestation(_notary, _attestation);\n            // Guard doesn't receive anything, as Notary wasn't slashed using the Fraud Report\n            _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n            /**\n             * TODO: design incentives for the reporter in a way, where they get less\n             * by reporting directly instead of using a correct Fraud Report.\n             * That will allow Guards to focus on Report signing and don't worry\n             * about submitReport (whether their own or outsourced) txs being frontrun.\n             */\n        }\n    }\n\n    /**\n     * @notice Checks if a submitted Report is a correct Report. Reported Attestation\n     * can be either valid or fraud. Report flag can also be either Valid or Fraud.\n     * Report is correct if its flag matches the Attestation validity.\n     * 1. Attestation: valid, Flag: Fraud.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     * 2. Attestation: valid, Flag: Valid.\n     *      Report is deemed correct, no action is done.\n     * 3. Attestation: Fraud, Flag: Fraud.\n     *      Report is deemed correct, Notary is slashed (if they haven't been already).\n     * 4. Attestation: Fraud, Flag: Valid.\n     *      Report is deemed incorrect, Guard is slashed (if they haven't been already).\n     *      Notary is slashed (if they haven't been already), but Guard doesn't receive\n     *      any rewards (as their report indicated that the attestation was valid).\n     *\n     * A \"Fraud\" Attestation is a (_destination, _nonce, _root) attestation that doesn't correspond\n     * with the historical state of Origin contract. Either of these needs to be true:\n     * - _nonce is higher than current nonce for _destination (no root exists for this nonce)\n     * - _root is not equal to the historical root of _nonce for _destination\n     * This would mean that message(s) that were not truly\n     * dispatched on Origin were falsely included in the signed root.\n     *\n     * A Fraud Attestation will only be accepted as valid by the Mirror.\n     * If a Fraud Attestation is submitted to the Mirror, a Guard should\n     * submit a Fraud Report using Origin.submitReport()\n     * in order to slash the Notary with a Fraud Attestation.\n     *\n     * @dev Both Notary and Guard signatures and roles have been checked in ReportHub,\n     * hence `_notary` is an active Notary, `_guard` is an active Guard at this point.\n     *\n     * @param _guard            Guard address (signature\u0026role already verified)\n     * @param _notary           Notary address (signature\u0026role already verified)\n     * @param _attestationView  Memory view over reported Attestation\n     * @param _reportView       Memory view over Report\n     * @param _report           Payload with Report data and signature\n     * @return TRUE if Report was correct (implying Guard was not slashed)\n     */\n    function _handleReport(\n        address _guard,\n        address _notary,\n        bytes29 _attestationView,\n        bytes29 _reportView,\n        bytes memory _report\n    ) internal override returns (bool) {\n        uint32 attestedDestination = _attestationView.attestedDestination();\n        uint32 attestedNonce = _attestationView.attestedNonce();\n        bytes32 attestedRoot = _attestationView.attestedRoot();\n        if (_isValidAttestation(attestedDestination, attestedNonce, attestedRoot)) {\n            // Attestation: Valid\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                return false;\n            } else {\n                // Flag: Valid\n                // Report is correct, no action needed\n                return true;\n            }\n        } else {\n            // Attestation: Fraud\n            if (_reportView.reportedFraud()) {\n                // Flag: Fraud\n                // Report is correct, slash the Notary\n                emit CorrectFraudReport(_guard, _report);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: _guard });\n                return true;\n            } else {\n                // Flag: Valid\n                // Report is incorrect, slash the Guard\n                emit IncorrectReport(_guard, _report);\n                _slashGuard(_guard);\n                emit FraudAttestation(_notary, _attestationView.clone());\n                // Guard doesn't receive anything due to Valid flag on the Report\n                _slashNotary({ _domain: _localDomain(), _notary: _notary, _guard: address(0) });\n                return false;\n            }\n        }\n    }\n\n    /**\n     * @notice Inserts a merkle root for an empty merkle tree into the historical roots array\n     * for the given destination.\n     * @dev This enables:\n     * - Counting nonces from 1 (nonce=0 meaning no messages have been sent).\n     * - Not slashing the Notaries for signing an attestation for an empty tree\n     * (assuming they sign the correct root outlined below).\n     */\n    function _initializeHistoricalRoots(uint32 _destination) internal {\n        // This function should only be called only if the array is empty\n        assert(historicalRoots[_destination].length == 0);\n        // Insert a historical root so nonces start at 1 rather then 0.\n        // Here we insert the root of an empty merkle tree\n        historicalRoots[_destination].push(EMPTY_TREE_ROOT);\n        historicalNonceBlockNumbers[_destination].push(0);\n    }\n\n    /**\n     * @notice Inserts new message into the Merkle tree for the given destination\n     * and stores the new merkle root.\n     * @param _destination  Destination domain of the dispatched message\n     * @param _messageNonce Nonce of the dispatched message\n     * @param _messageHash  Hash of the dispatched message\n     */\n    function _insertMessage(\n        uint32 _destination,\n        uint32 _messageNonce,\n        bytes32 _messageHash\n    ) internal {\n        // TODO: when Notary is active on Destination, initialize historical roots\n        // upon adding a first Notary for given destination\n        if (historicalRoots[_destination].length == 0) _initializeHistoricalRoots(_destination);\n        /// @dev _messageNonce == tree.count() + 1\n        // tree.insert() requires amount of leaves AFTER the leaf insertion (i.e. tree.count() + 1)\n        trees[_destination].insert(_messageNonce, _messageHash);\n        /// @dev leaf is inserted =\u003e _messageNonce == tree.count()\n        // tree.root() requires current amount of leaves (i.e. tree.count())\n        historicalRoots[_destination].push(trees[_destination].root(_messageNonce));\n        historicalNonceBlockNumbers[_destination].push(block.number);\n    }\n\n    /**\n     * @notice Child contract should implement the slashing logic for Notaries\n     * with all the required system calls.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _domain   Domain where the reported Notary is active\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal virtual;\n\n    /**\n     * @notice Child contract should implement the slashing logic for Guards\n     * with all the required system calls.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal virtual;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns whether (_destination, _nonce, _root) matches the historical state\n     * of the Merkle Tree for that destination.\n     * @dev For `_nonce == 0`: root has to match `EMPTY_TREE_ROOT` (root of an empty merkle tree)\n     * For `_nonce != 0`:\n     * - There has to be at least `_nonce` messages sent to `_destination`\n     * - Merkle root after sending message with `nonce == _nonce` should match `_root`\n     */\n    function _isValidAttestation(\n        uint32 _destination,\n        uint32 _nonce,\n        bytes32 _root\n    ) internal view returns (bool) {\n        if (_nonce \u003c historicalRoots[_destination].length) {\n            // If a nonce exists for a given destination,\n            // a root should match the historical root\n            return _root == historicalRoots[_destination][_nonce];\n        }\n        // If a nonce doesn't exist for a given destination,\n        // it should be a zero nonce with a root of an empty merkle tree\n        return _nonce == 0 \u0026\u0026 _root == EMPTY_TREE_ROOT;\n    }\n\n    /**\n     * @notice Returns amount of leaves in the merkle tree for the given destination.\n     * @dev Every inserted leaf leads to adding a historical root,\n     * removing the necessity to store amount of leaves separately.\n     * Historical roots array is initialized with a root of an empty Merkle tree,\n     * thus actual amount of leaves is lower by one.\n     */\n    function _getTreeCount(uint32 _destination) internal view returns (uint256) {\n        // if no historical roots are saved, destination is unknown, and there were\n        // no dispatched messages to that destination\n        if (historicalRoots[_destination].length == 0) return 0;\n        // We subtract 1, as the very first inserted root is EMPTY_TREE_ROOT\n        return historicalRoots[_destination].length - 1;\n    }\n}\n\n//\n\nlibrary TypeCasts {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    function coerceBytes32(string memory _s) internal pure returns (bytes32 _b) {\n        _b = bytes(_s).ref(0).index(0, uint8(bytes(_s).length));\n    }\n\n    // treat it as a null-terminated string of max 32 bytes\n    function coerceString(bytes32 _buf) internal pure returns (string memory _newStr) {\n        uint8 _slen = 0;\n        while (_slen \u003c 32 \u0026\u0026 _buf[_slen] != 0) {\n            _slen++;\n        }\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _newStr := mload(0x40)\n            mstore(0x40, add(_newStr, 0x40)) // may end up with extra\n            mstore(_newStr, _slen)\n            mstore(add(_newStr, 0x20), _buf)\n        }\n    }\n\n    // alignment preserving cast\n    function addressToBytes32(address _addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(_addr)));\n    }\n\n    // alignment preserving cast\n    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {\n        return address(uint160(uint256(_buf)));\n    }\n}\n\nlibrary Header {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant HEADER_VERSION = 1;\n\n    /**\n     * @dev Header memory layout\n     * [000 .. 002): version            uint16   2 bytes\n     * [002 .. 006): origin             uint32   4 bytes\n     * [006 .. 038): sender             bytes32 32 bytes\n     * [038 .. 042): nonce              uint32   4 bytes\n     * [042 .. 046): destination        uint32   4 bytes\n     * [046 .. 078): recipient          bytes32 32 bytes\n     * [078 .. 082): optimisticSeconds  uint32   4 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_ORIGIN = 2;\n    uint256 internal constant OFFSET_SENDER = 6;\n    uint256 internal constant OFFSET_NONCE = 38;\n    uint256 internal constant OFFSET_DESTINATION = 42;\n    uint256 internal constant OFFSET_RECIPIENT = 46;\n    uint256 internal constant OFFSET_OPTIMISTIC_SECONDS = 78;\n\n    uint256 internal constant HEADER_LENGTH = 82;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyHeader(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_HEADER);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a header payload.\n     */\n    function castToHeader(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_HEADER);\n    }\n\n    /**\n     * @notice Returns a formatted Header payload with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @return Formatted header\n     **/\n    function formatHeader(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                HEADER_VERSION,\n                _origin,\n                _sender,\n                _nonce,\n                _destination,\n                _recipient,\n                _optimisticSeconds\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Header.\n     */\n    function isHeader(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return headerVersion(_view) == HEADER_VERSION \u0026\u0026 length == HEADER_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            HEADER SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns header's version field.\n    function headerVersion(bytes29 _header) internal pure onlyHeader(_header) returns (uint16) {\n        return uint16(_header.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns header's origin field\n    function origin(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_ORIGIN, 4));\n    }\n\n    /// @notice Returns header's sender field\n    function sender(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_SENDER, 32);\n    }\n\n    /// @notice Returns header's nonce field\n    function nonce(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_NONCE, 4));\n    }\n\n    /// @notice Returns header's destination field\n    function destination(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_DESTINATION, 4));\n    }\n\n    /// @notice Returns header's recipient field as bytes32\n    function recipient(bytes29 _header) internal pure onlyHeader(_header) returns (bytes32) {\n        return _header.index(OFFSET_RECIPIENT, 32);\n    }\n\n    /// @notice Returns header's optimistic seconds field\n    function optimisticSeconds(bytes29 _header) internal pure onlyHeader(_header) returns (uint32) {\n        return uint32(_header.indexUint(OFFSET_OPTIMISTIC_SECONDS, 4));\n    }\n\n    /// @notice Returns header's recipient field as an address\n    function recipientAddress(bytes29 _header) internal pure returns (address) {\n        return TypeCasts.bytes32ToAddress(recipient(_header));\n    }\n}\n\nlibrary Tips {\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    uint16 internal constant TIPS_VERSION = 1;\n\n    // TODO: determine if we need to pack the tips values,\n    // or if using uint256 instead will suffice.\n\n    /**\n     * @dev Tips memory layout\n     * [000 .. 002): version            uint16\t 2 bytes\n     * [002 .. 014): notaryTip          uint96\t12 bytes\n     * [014 .. 026): broadcasterTip     uint96\t12 bytes\n     * [026 .. 038): proverTip          uint96\t12 bytes\n     * [038 .. 050): executorTip        uint96\t12 bytes\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n    uint256 internal constant OFFSET_NOTARY = 2;\n    uint256 internal constant OFFSET_BROADCASTER = 14;\n    uint256 internal constant OFFSET_PROVER = 26;\n    uint256 internal constant OFFSET_EXECUTOR = 38;\n\n    uint256 internal constant TIPS_LENGTH = 50;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyTips(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE_TIPS);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a tips payload.\n     */\n    function castToTips(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE_TIPS);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload with provided fields\n     * @param _notaryTip        Tip for the Notary\n     * @param _broadcasterTip   Tip for the Broadcaster\n     * @param _proverTip        Tip for the Prover\n     * @param _executorTip      Tip for the Executor\n     * @return Formatted tips\n     **/\n    function formatTips(\n        uint96 _notaryTip,\n        uint96 _broadcasterTip,\n        uint96 _proverTip,\n        uint96 _executorTip\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(TIPS_VERSION, _notaryTip, _broadcasterTip, _proverTip, _executorTip);\n    }\n\n    /**\n     * @notice Returns a formatted Tips payload specifying empty tips.\n     * @return Formatted tips\n     **/\n    function emptyTips() internal pure returns (bytes memory) {\n        return formatTips(0, 0, 0, 0);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Tips payload.\n     */\n    function isTips(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version exists in the payload\n        if (length \u003c 2) return false;\n        // Check that header version and its length matches\n        return tipsVersion(_view) == TIPS_VERSION \u0026\u0026 length == TIPS_LENGTH;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             TIPS SLICING                             ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns version of formatted tips\n    function tipsVersion(bytes29 _tips) internal pure onlyTips(_tips) returns (uint16) {\n        return uint16(_tips.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns notaryTip field\n    function notaryTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_NOTARY, 12));\n    }\n\n    /// @notice Returns broadcasterTip field\n    function broadcasterTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_BROADCASTER, 12));\n    }\n\n    /// @notice Returns proverTip field\n    function proverTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_PROVER, 12));\n    }\n\n    /// @notice Returns executorTip field\n    function executorTip(bytes29 _tips) internal pure onlyTips(_tips) returns (uint96) {\n        return uint96(_tips.indexUint(OFFSET_EXECUTOR, 12));\n    }\n\n    /// @notice Returns total tip amount.\n    function totalTips(bytes29 _tips) internal pure returns (uint96) {\n        // In practice there's no chance that the total tips value would not fit into uint96.\n        // TODO: determine if we want to use uint256 here instead anyway.\n        return notaryTip(_tips) + broadcasterTip(_tips) + proverTip(_tips) + executorTip(_tips);\n    }\n}\n\nlibrary Message {\n    using Header for bytes29;\n    using Tips for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    enum Parts {\n        Version,\n        Header,\n        Tips,\n        Body\n    }\n\n    /**\n     * @dev This is only updated if the whole message structure is changed,\n     *      i.e. if a new part is added.\n     *      If already existing part is changed, the message version does not get bumped.\n     */\n    uint16 internal constant MESSAGE_VERSION = 1;\n\n    /**\n     * @dev Message memory layout\n     * [000 .. 002): version            uint16  2 bytes\n     * [002 .. 004): header length      uint16  2 bytes (length == AAA - 6)\n     * [004 .. 006): tips length        uint16  2 bytes (length == BBB - AAA)\n     * [006 .. AAA): header             bytes   ? bytes\n     * [AAA .. BBB): tips               bytes   ? bytes\n     * [BBB .. CCC): body               bytes   ? bytes (length could be zero)\n     */\n\n    uint256 internal constant OFFSET_VERSION = 0;\n\n    /// @dev How much bytes is used for storing the version, or a single offset value\n    uint8 internal constant TWO_BYTES = 2;\n    /// @dev This value reflects the header offset in the latest message version\n    uint16 internal constant OFFSET_HEADER = TWO_BYTES * uint8(type(Parts).max);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyMessage(bytes29 _view) {\n        _view.assertType(SynapseTypes.MESSAGE);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a message payload.\n     */\n    function castToMessage(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.MESSAGE);\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        // Header and Tips are supposed to fit within 65535 bytes\n        return\n            abi.encodePacked(\n                MESSAGE_VERSION,\n                uint16(_header.length),\n                uint16(_tips.length),\n                _header,\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Returns formatted message with provided fields\n     * @param _origin               Domain of origin chain\n     * @param _sender               Address that sent the message\n     * @param _nonce                Message nonce on origin chain\n     * @param _destination          Domain of destination chain\n     * @param _recipient            Address that will receive the message\n     * @param _optimisticSeconds    Optimistic period for message execution\n     * @param _tips                 Formatted tips payload\n     * @param _messageBody          Raw bytes of message body\n     * @return Formatted message\n     **/\n    function formatMessage(\n        uint32 _origin,\n        bytes32 _sender,\n        uint32 _nonce,\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes memory) {\n        return\n            formatMessage(\n                Header.formatHeader(\n                    _origin,\n                    _sender,\n                    _nonce,\n                    _destination,\n                    _recipient,\n                    _optimisticSeconds\n                ),\n                _tips,\n                _messageBody\n            );\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted Message.\n     */\n    function isMessage(bytes29 _view) internal pure returns (bool) {\n        uint256 length = _view.len();\n        // Check if version and lengths exist in the payload\n        if (length \u003c OFFSET_HEADER) return false;\n        // Check message version\n        if (messageVersion(_view) != MESSAGE_VERSION) return false;\n\n        uint256 headerLength = _loadLength(_view, Parts.Header);\n        uint256 tipsLength = _loadLength(_view, Parts.Tips);\n        // Header and Tips need to exist\n        // Body could be empty, thus \u003e\n        if (OFFSET_HEADER + headerLength + tipsLength \u003e length) return false;\n\n        // Check header for being a formatted header payload\n        // Check tips for being a formatted tips payload\n        if (!header(_view).isHeader() || !tips(_view).isTips()) return false;\n        return true;\n    }\n\n    /**\n     * @notice Returns leaf of formatted message with provided fields.\n     * @param _header       Formatted header payload\n     * @param _tips         Formatted tips payload\n     * @param _messageBody  Raw bytes of message body\n     * @return Leaf (hash) of formatted message\n     **/\n    function messageHash(\n        bytes memory _header,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) internal pure returns (bytes32) {\n        return keccak256(formatMessage(_header, _tips, _messageBody));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                           MESSAGE SLICING                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /// @notice Returns message's version field.\n    function messageVersion(bytes29 _view) internal pure onlyMessage(_view) returns (uint16) {\n        return uint16(_view.indexUint(OFFSET_VERSION, 2));\n    }\n\n    /// @notice Returns message's header field as bytes29 pointer.\n    function header(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER,\n                _loadLength(_view, Parts.Header),\n                SynapseTypes.MESSAGE_HEADER\n            );\n    }\n\n    /// @notice Returns message's tips field as bytes29 pointer.\n    function tips(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.slice(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header),\n                _loadLength(_view, Parts.Tips),\n                SynapseTypes.MESSAGE_TIPS\n            );\n    }\n\n    /// @notice Returns message's body field as bytes29 pointer.\n    function body(bytes29 _view) internal pure onlyMessage(_view) returns (bytes29) {\n        return\n            _view.sliceFrom(\n                OFFSET_HEADER + _loadLength(_view, Parts.Header) + _loadLength(_view, Parts.Tips),\n                SynapseTypes.RAW_BYTES\n            );\n    }\n\n    /// @notice Loads length for a given part of the message\n    function _loadLength(bytes29 _view, Parts _part) private pure returns (uint256) {\n        return _view.indexUint(uint256(_part) * TWO_BYTES, TWO_BYTES);\n    }\n}\n\nlibrary SystemCall {\n    using ByteString for bytes29;\n    using TypedMemView for bytes;\n    using TypedMemView for bytes29;\n\n    /**\n     * @dev Custom address, used for sending and receiving system messages.\n     *      Origin is supposed to dispatch messages from SystemRouter\n     *      as if they were sent by this address.\n     *      Destination is supposed to reroute messages for this address to SystemRouter.\n     *\n     *      Note: all bits except for lower 20 bytes are set to 1.\n     *      Note: TypeCasts.bytes32ToAddress(SYSTEM_ROUTER) == address(0)\n     */\n    bytes32 internal constant SYSTEM_ROUTER = bytes32(type(uint256).max \u003c\u003c 160);\n\n    /**\n     * @dev SystemCall memory layout\n     * [000 .. 001): recipient      uint8   1 bytes\n     * [001 .. END]: payload        bytes   ? bytes\n     */\n\n    uint256 internal constant OFFSET_CALL_RECIPIENT = 0;\n    uint256 internal constant OFFSET_CALL_PAYLOAD = 1;\n\n    /**\n     * @dev System Router is supposed to modify (rootSubmittedAt, origin, caller)\n     * in the given payload, meaning for a valid system call payload\n     * there has to exist at least three arguments, occupying at least three words in total.\n     */\n    uint256 internal constant PAYLOAD_MIN_ARGUMENT_WORDS = 3;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    modifier onlyType(bytes29 _view, uint40 _type) {\n        _view.assertType(_type);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              FORMATTERS                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns a formatted System Call payload with provided fields.\n     * See: formatAdjustedCallPayload() for more details.\n     * @param _systemRecipient  System Contract to receive message\n     *                          (see ISystemRouter.SystemEntity)\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Formatted System Call payload.\n     */\n    function formatSystemCall(\n        uint8 _systemRecipient,\n        bytes29 _payload,\n        bytes29 _prefix\n    ) internal view returns (bytes memory) {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](4);\n        // First byte is encoded system recipient\n        views[0] = abi.encodePacked(_systemRecipient).ref(SynapseTypes.RAW_BYTES);\n        // Use payload's function selector\n        views[1] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[2] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[3] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Constructs the call payload having the first arguments replaced with given prefix.\n     * @dev Given:\n     * - `payload = abi.encodeWithSelector(foo.selector, a0, b0, c0, d0, e0);`\n     * - `prefix = abi.encode(a1, b1, c1);`\n     * - `a`, `b`, `c` are static type arguments\n     *      Then:\n     * - Existing payload will trigger `foo(a0, b0, c0, d0, e0)`\n     * - Adjusted payload will trigger `foo(a1, b1, c1, d0, e0)`\n     * @param _payload  Memory view over call payload where the first arguments need to be replaced\n     * @param _prefix   abi encoded arguments to use as the first arguments in the adjusted payload\n     * @return Adjusted call payload with replaced first arguments\n     */\n    function formatAdjustedCallPayload(bytes29 _payload, bytes29 _prefix)\n        internal\n        view\n        returns (bytes memory)\n    {\n        bytes29 arguments = _payload.argumentsPayload();\n        // Arguments payload should be at least as long as the replacement prefix\n        require(arguments.len() \u003e= _prefix.len(), \"Payload too short\");\n        bytes29[] memory views = new bytes29[](3);\n        // Use payload's function selector\n        views[0] = _payload.callSelector();\n        // Use prefix as the first arguments\n        views[1] = _prefix;\n        // Use payload's remaining arguments (following prefix)\n        views[2] = arguments.sliceFrom({ _index: _prefix.len(), newType: SynapseTypes.RAW_BYTES });\n        return TypedMemView.join(views);\n    }\n\n    /**\n     * @notice Returns a properly typed bytes29 pointer for a system call payload.\n     */\n    function castToSystemCall(bytes memory _payload) internal pure returns (bytes29) {\n        return _payload.ref(SynapseTypes.SYSTEM_CALL);\n    }\n\n    /**\n     * @notice Checks that a payload is a formatted System Call.\n     */\n    function isSystemCall(bytes29 _view) internal pure returns (bool) {\n        // Payload needs to exist (system calls are never done via fallback function)\n        if (_view.len() \u003c OFFSET_CALL_PAYLOAD) return false;\n        bytes29 payload = _callPayload(_view);\n        // Payload needs to be a proper call payload\n        if (!payload.isCallPayload()) return false;\n        // Payload needs to have at least this amount of argument words\n        return payload.argumentWords() \u003e= PAYLOAD_MIN_ARGUMENT_WORDS;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                         SYSTEM CALL SLICING                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns int value of System Call's recipient (see ISystemRouter.SystemEntity).\n     */\n    function callRecipient(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (uint8)\n    {\n        return uint8(_view.indexUint({ _index: OFFSET_CALL_RECIPIENT, _bytes: 1 }));\n    }\n\n    /**\n     * @notice Returns System Call's payload.\n     */\n    function callPayload(bytes29 _view)\n        internal\n        pure\n        onlyType(_view, SynapseTypes.SYSTEM_CALL)\n        returns (bytes29)\n    {\n        return _callPayload(_view);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          PRIVATE FUNCTIONS                           ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns System Call's payload WITHOUT checking the view type.\n     * To be used in `isSystemCall`, where type check is not necessary.\n     */\n    function _callPayload(bytes29 _view) private pure returns (bytes29) {\n        return _view.sliceFrom({ _index: OFFSET_CALL_PAYLOAD, newType: SynapseTypes.CALL_PAYLOAD });\n    }\n}\n\ninterface ISystemRouter {\n    /// @dev Potential senders/recipients of a system message\n    enum SystemEntity {\n        Origin,\n        Destination\n    }\n\n    /**\n     * @notice Call a System Contract on the destination chain with a given data payload.\n     * Note: for system calls on the local chain\n     * - use `destination = localDomain`\n     * - `_optimisticSeconds` value will be ignored\n     *\n     * @dev Only System contracts are allowed to call this function.\n     * Note: knowledge of recipient address is not required, routing will be done by SystemRouter\n     * on the destination chain. Following call will be made on destination chain:\n     * - recipient.call(_data, callOrigin, systemCaller, rootSubmittedAt)\n     * This allows recipient to check:\n     * - callOrigin: domain where a system call originated (local domain in this case)\n     * - systemCaller: system entity who initiated the call (msg.sender on local chain)\n     * - rootSubmittedAt:\n     *   - For cross-chain calls: timestamp when merkle root (used for executing the system call)\n     *     was submitted to destination and its optimistic timer started ticking\n     *   - For on-chain calls: timestamp of the current block\n     *\n     * @param _destination          Domain of destination chain\n     * @param _optimisticSeconds    Optimistic period for the message\n     * @param _recipient            System entity to receive the call on destination chain\n     * @param _data                 Data for calling recipient on destination chain\n     */\n    function systemCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes[] memory _dataArray\n    ) external;\n\n    /**\n     * @notice Calls a few system contracts using the same calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity[] memory _recipients,\n        bytes memory _data\n    ) external;\n\n    /**\n     * @notice Calls a single system contract a few times using the given calldata for each call.\n     * See `systemCall` for details on system calls.\n     * Note: tx will revert if any of the calls revert, guaranteeing\n     * that either all calls succeed or none.\n     */\n    function systemMultiCall(\n        uint32 _destination,\n        uint32 _optimisticSeconds,\n        SystemEntity _recipient,\n        bytes[] memory _dataArray\n    ) external;\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)\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 * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\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 Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = _setInitializedVersion(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     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\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    modifier reinitializer(uint8 version) {\n        bool isTopLevelCall = _setInitializedVersion(version);\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(version);\n        }\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        require(_initializing, \"Initializable: contract is not initializing\");\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    function _disableInitializers() internal virtual {\n        _setInitializedVersion(type(uint8).max);\n    }\n\n    function _setInitializedVersion(uint8 version) private returns (bool) {\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\n        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level\n        // of initializers, because in other contexts the contract may have been reentered.\n        if (_initializing) {\n            require(\n                version == 1 \u0026\u0026 !AddressUpgradeable.isContract(address(this)),\n                \"Initializable: contract is already initialized\"\n            );\n            return false;\n        } else {\n            require(_initialized \u003c version, \"Initializable: contract is already initialized\");\n            _initialized = version;\n            return true;\n        }\n    }\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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    /**\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[50] private __gap;\n}\n\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\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\nabstract contract SystemContract is DomainContext, OwnableUpgradeable {\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // domain of the Synapse Chain\n    // Answer to the Ultimate Question of Life, the Universe, and Everything\n    // And answer to less important questions wink wink\n    uint32 public constant SYNAPSE_DOMAIN = 4269;\n    // TODO: replace the placeholder with actual value\n\n    uint256 internal constant ORIGIN = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Origin);\n    uint256 internal constant DESTINATION = 1 \u003c\u003c uint8(ISystemRouter.SystemEntity.Destination);\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    ISystemRouter public systemRouter;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on all chains (either local or remote).\n     * Note: any function protected by this modifier should have last three params:\n     * - uint32 _callOrigin\n     * - SystemEntity _systemCaller\n     * - uint256 _rootSubmittedAt\n     * Make sure to check domain/caller, if a function should be only called\n     * from a given domain / by a given caller.\n     * Make sure to check that a needed amount of time has passed since\n     * root submission for the cross-chain calls.\n     */\n    modifier onlySystemRouter() {\n        _assertSystemRouter();\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on Synapse chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     */\n    modifier onlySynapseChain(uint32 _originDomain) {\n        require(_originDomain == SYNAPSE_DOMAIN, \"!synapseDomain\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * a set of System Contracts on any chain.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: check constants section for existing mask constants\n     * E.g. to restrict the set of callers to three allowed system callers:\n     *  onlyCallers(MASK_0 | MASK_1 | MASK_2, _systemCaller)\n     */\n    modifier onlyCallers(uint256 _allowedMask, ISystemRouter.SystemEntity _systemCaller) {\n        require(_entityAllowed(_allowedMask, _systemCaller), \"!allowedCaller\");\n        _;\n    }\n\n    /**\n     * @dev Modifier for functions that are supposed to be called only from\n     * System Contracts on remote chain with a defined minimum optimistic period.\n     * Note: has to be used alongside with `onlySystemRouter`\n     * See `onlySystemRouter` for details about the functions protected by such modifiers.\n     * Note: message could be sent with a period lower than that, but will be executed\n     * only when `_optimisticSeconds` have passed.\n     * Note: _optimisticSeconds=0 will allow calls from a local chain as well\n     */\n    modifier onlyOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds) {\n        _assertOptimisticPeriodOver(_rootSubmittedAt, _optimisticSeconds);\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __SystemContract_initialize() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              OWNER ONLY                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line ordering\n    function setSystemRouter(ISystemRouter _systemRouter) external onlyOwner {\n        systemRouter = _systemRouter;\n    }\n\n    /**\n     * @dev Should be impossible to renounce ownership;\n     * we override OpenZeppelin OwnableUpgradeable's\n     * implementation of renounceOwnership to make it a no-op\n     */\n    function renounceOwnership() public override onlyOwner {} //solhint-disable-line no-empty-blocks\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function _assertSystemRouter() internal view {\n        require(msg.sender == address(systemRouter), \"!systemRouter\");\n    }\n\n    function _assertOptimisticPeriodOver(uint256 _rootSubmittedAt, uint256 _optimisticSeconds)\n        internal\n        view\n    {\n        require(block.timestamp \u003e= _rootSubmittedAt + _optimisticSeconds, \"!optimisticPeriod\");\n    }\n\n    /**\n     * @notice Checks if a given entity is allowed to call a function using a _systemMask\n     * @param _systemMask a mask of allowed entities\n     * @param _entity a system entity to check\n     * @return true if _entity is allowed to call a function\n     *\n     * @dev this function works by converting the enum value to a non-zero bit mask\n     * we then use a bitwise AND operation to check if permission bits allow the entity\n     * to perform this operation, more details can be found here:\n     * https://en.wikipedia.org/wiki/Bitwise_operation#AND\n     */\n    function _entityAllowed(uint256 _systemMask, ISystemRouter.SystemEntity _entity)\n        internal\n        pure\n        returns (bool)\n    {\n        return _systemMask \u0026 _getSystemMask(_entity) != 0;\n    }\n\n    /**\n     * @notice Returns a mask for a given system entity\n     * @param _entity System entity\n     * @return a non-zero mask for a given system entity\n     *\n     * Converts an enum value into a non-zero bit mask used for a bitwise AND check\n     * E.g. for Origin (0) returns 1, for Destination (1) returns 2\n     */\n    function _getSystemMask(ISystemRouter.SystemEntity _entity) internal pure returns (uint256) {\n        return 1 \u003c\u003c uint8(_entity);\n    }\n}\n\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length \u003e 0;\n    }\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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length \u003e 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(errorMessage);\n            }\n        }\n    }\n}\n\ncontract Origin is Version0, OriginEvents, SystemContract, LocalDomainContext, OriginHub {\n    using Tips for bytes;\n    using Tips for bytes29;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              CONSTANTS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // Maximum bytes per message = 2 KiB\n    // (somewhat arbitrarily set to begin)\n    uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                               STORAGE                                ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // contract responsible for Notary bonding, slashing and rotation\n    // TODO: use \"bonding manager\" instead when implemented\n    INotaryManager public notaryManager;\n\n    // gap for upgrade safety\n    uint256[49] private __GAP; //solhint-disable-line var-name-mixedcase\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                              MODIFIERS                               ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Ensures that function is called by the NotaryManager contract\n     */\n    modifier onlyNotaryManager() {\n        require(msg.sender == address(notaryManager), \"!notaryManager\");\n        _;\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             CONSTRUCTOR                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(uint32 _domain) LocalDomainContext(_domain) {}\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                             INITIALIZER                              ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    function initialize(INotaryManager _notaryManager) external initializer {\n        __SystemContract_initialize();\n        _setNotaryManager(_notaryManager);\n        _addNotary(notaryManager.notary());\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                    EXTERNAL FUNCTIONS: RESTRICTED                    ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set a new Notary\n     * @dev To be set when rotating Notary after Fraud\n     * @param _notary the new Notary\n     */\n    function setNotary(address _notary) external onlyNotaryManager {\n        /**\n         * TODO: do this properly\n         * @dev 1. New Notaries should be added to all System Contracts\n         *      from \"secondary\" Bonding contracts (global Notary/Guard registry)\n         *      1a. onlyNotaryManager -\u003e onlyBondingManager (or w/e the name would be)\n         *      2. There is supposed to be more than one active Notary\n         *      2a. setNotary() -\u003e addNotary()\n         */\n        _addNotary(_notary);\n    }\n\n    /**\n     * @notice Set a new NotaryManager contract\n     * @dev Origin(s) will initially be initialized using a trusted NotaryManager contract;\n     * we will progressively decentralize by swapping the trusted contract with a new implementation\n     * that implements Notary bonding \u0026 slashing, and rules for Notary selection \u0026 rotation\n     * @param _notaryManager the new NotaryManager contract\n     */\n    function setNotaryManager(address _notaryManager) external onlyOwner {\n        _setNotaryManager(INotaryManager(_notaryManager));\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          EXTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Dispatch the message to the destination domain \u0026 recipient\n     * @dev Format the message, insert its hash into Merkle tree,\n     * enqueue the new Merkle root, and emit `Dispatch` event with message information.\n     * @param _destination      Domain of destination chain\n     * @param _recipient        Address of recipient on destination chain as bytes32\n     * @param _messageBody      Raw bytes content of message\n     */\n    function dispatch(\n        uint32 _destination,\n        bytes32 _recipient,\n        uint32 _optimisticSeconds,\n        bytes memory _tips,\n        bytes memory _messageBody\n    ) external payable haveActiveNotary returns (uint32 messageNonce, bytes32 messageHash) {\n        // TODO: add unit tests covering return values\n        require(_messageBody.length \u003c= MAX_MESSAGE_BODY_BYTES, \"msg too long\");\n        bytes29 tips = _tips.castToTips();\n        // Check: tips payload is correctly formatted\n        require(tips.isTips(), \"!tips: formatting\");\n        // Check: total tips value matches msg.value\n        require(tips.totalTips() == msg.value, \"!tips: totalTips\");\n        // Latest nonce (i.e. \"last message\" nonce) is current amount of leaves in the tree.\n        // Message nonce is the amount of leaves after the new leaf insertion\n        messageNonce = nonce(_destination) + 1;\n        // format the message into packed bytes\n        bytes memory message = Message.formatMessage({\n            _origin: _localDomain(),\n            _sender: _checkForSystemRouter(_recipient),\n            _nonce: messageNonce,\n            _destination: _destination,\n            _recipient: _recipient,\n            _optimisticSeconds: _optimisticSeconds,\n            _tips: _tips,\n            _messageBody: _messageBody\n        });\n        messageHash = keccak256(message);\n        // insert the hashed message into the Merkle tree\n        _insertMessage(_destination, messageNonce, messageHash);\n        // Emit Dispatch event with message information\n        // note: leaf index in the tree is messageNonce - 1, meaning we don't need to emit that\n        emit Dispatch(messageHash, messageNonce, _destination, _tips, message);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                          INTERNAL FUNCTIONS                          ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Set the NotaryManager\n     * @param _notaryManager Address of the NotaryManager\n     */\n    function _setNotaryManager(INotaryManager _notaryManager) internal {\n        require(Address.isContract(address(_notaryManager)), \"!contract notaryManager\");\n        notaryManager = INotaryManager(_notaryManager);\n        emit NewNotaryManager(address(_notaryManager));\n    }\n\n    /**\n     * @notice Slash the Notary.\n     * @dev Called when fraud is proven (Fraud Attestation).\n     * @param _notary   Notary to slash\n     * @param _guard    Guard who reported fraudulent Notary [address(0) if not a Guard report]\n     */\n    function _slashNotary(\n        uint32 _domain,\n        address _notary,\n        address _guard\n    ) internal override {\n        // _notary is always an active Notary at this point\n        _removeNotary(_domain, _notary);\n        notaryManager.slashNotary(payable(msg.sender));\n        // TODO: add domain to the event (decide what fields need to be indexed)\n        emit NotarySlashed(_notary, _guard, msg.sender);\n    }\n\n    /**\n     * @notice Slash the Guard.\n     * @dev Called when guard misbehavior is proven (Incorrect Report).\n     * @param _guard    Guard to slash\n     */\n    function _slashGuard(address _guard) internal override {\n        // _guard is always an active Guard at this point\n        _removeGuard(_guard);\n        emit GuardSlashed(_guard, msg.sender);\n    }\n\n    /*╔══════════════════════════════════════════════════════════════════════╗*\\\n    ▏*║                            INTERNAL VIEWS                            ║*▕\n    \\*╚══════════════════════════════════════════════════════════════════════╝*/\n\n    /**\n     * @notice Returns adjusted \"sender\" field.\n     * @dev By default, \"sender\" field is msg.sender address casted to bytes32.\n     * However, if SYSTEM_ROUTER is used for \"recipient\" field, and msg.sender is SystemRouter,\n     * SYSTEM_ROUTER is also used as \"sender\" field.\n     * Note: tx will revert if anyone but SystemRouter uses SYSTEM_ROUTER as the recipient.\n     */\n    function _checkForSystemRouter(bytes32 _recipient) internal view returns (bytes32 sender) {\n        if (_recipient != SystemCall.SYSTEM_ROUTER) {\n            sender = TypeCasts.addressToBytes32(msg.sender);\n            /**\n             * @dev Note: SYSTEM_ROUTER has only the highest 12 bytes set,\n             * whereas TypeCasts.addressToBytes32 sets only the lowest 20 bytes.\n             * Thus, in this branch: sender != SystemCall.SYSTEM_ROUTER\n             */\n        } else {\n            // Check that SystemRouter specified SYSTEM_ROUTER as recipient, revert otherwise.\n            _assertSystemRouter();\n            // Adjust \"sender\" field for correct processing on remote chain.\n            sender = SystemCall.SYSTEM_ROUTER;\n        }\n    }\n}\n\nabstract contract NotaryManagerEvents {\n    /**\n     * @notice Emitted when a new origin is set\n     * @param origin The address of the new origin contract\n     */\n    event NewOrigin(address origin);\n\n    /**\n     * @notice Emitted when a new notary is set\n     * @param notary The address of the new notary\n     */\n    event NewNotary(address notary);\n\n    /**\n     * @notice Emitted when slashNotary is called\n     */\n    event FakeSlashed(address reporter);\n}\n\n// \n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\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 Context {\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\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n// \n// ============ Internal Imports ============\n// ============ External Imports ============\n/**\n * @title NotaryManager\n * @author Illusory Systems Inc.\n * @notice MVP / centralized version of contract\n * that will manage Notary bonding, slashing,\n * selection and rotation\n */\ncontract NotaryManager is NotaryManagerEvents, INotaryManager, Ownable {\n    // ============ Public Storage ============\n\n    // address of origin contract\n    address public origin;\n\n    // ============ Private Storage ============\n\n    // address of the current notary\n    address private _notary;\n\n    // ============ Modifiers ============\n\n    /**\n     * @notice Require that the function is called\n     * by the Origin contract\n     */\n    modifier onlyOrigin() {\n        require(msg.sender == origin, \"!origin\");\n        _;\n    }\n\n    // ============ Constructor ============\n\n    constructor(address _notaryAddress) payable Ownable() {\n        _notary = _notaryAddress;\n    }\n\n    // ============ External Functions ============\n\n    /**\n     * @notice Set the address of the a new origin contract\n     * @dev only callable by trusted owner\n     * @param _origin The address of the new origin contract\n     */\n    function setOrigin(address _origin) external onlyOwner {\n        require(Address.isContract(_origin), \"!contract origin\");\n        origin = _origin;\n\n        emit NewOrigin(_origin);\n    }\n\n    /**\n     * @notice Set the address of a new notary\n     * @dev only callable by trusted owner\n     * @param _notaryAddress The address of the new notary\n     */\n    function setNotary(address _notaryAddress) external onlyOwner {\n        _notary = _notaryAddress;\n        Origin(origin).setNotary(_notaryAddress);\n        emit NewNotary(_notaryAddress);\n    }\n\n    /**\n     * @notice Slashes the notary\n     * @dev Currently does nothing, functionality will be implemented later\n     * when notary bonding and rotation are also implemented\n     * @param _reporter The address of the entity that reported the notary fraud\n     */\n    function slashNotary(address payable _reporter) external override onlyOrigin {\n        emit FakeSlashed(_reporter);\n    }\n\n    /**\n     * @notice Get address of current notary\n     * @return the notary address\n     */\n    function notary() external view override returns (address) {\n        return _notary;\n    }\n\n    /**\n     * @dev should be impossible to renounce ownership;\n     * we override OpenZeppelin Ownable implementation\n     * of renounceOwnership to make it a no-op\n     */\n    // solhint-disable-next-line no-empty-blocks\n    function renounceOwnership() public override onlyOwner {\n        // do nothing\n    }\n}","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"2456:60:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"2456:60:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2480:33;;2512:1;2480:33;;;;;186:4:1;174:17;;;156:36;;144:2;129:18;2480:33:0;;;;;;","abiDefinition":[{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/NotaryManager.sol\":\"Version0\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/NotaryManager.sol\":{\"keccak256\":\"0xd158a75fd8c2d57b11ffe55dae571184dd25283a62a28783cdec623a549af01a\",\"urls\":[\"bzz-raw://b38ad59344cb8019d767b9cb7b13846d9d01a9a5585896c56632cf260e81cf96\",\"dweb:/ipfs/QmbUf22ZdywhRQnRL9mzug3GZkHevf6tHPT3yEkYzGjDUP\"]}},\"version\":1}"},"hashes":{"VERSION()":"ffa1ad74"}}}